Link to home
Create AccountLog in
Avatar of ThievingSix
ThievingSixFlag for United States of America

asked on

String Generation/Sequential Enumeration

Kind of a vague title I know, but I wasn't sure what to call it. This question isn't imperative but I was trying to figure it out for a while and would like another persons input so to speak.

My question is this:

I have a string comprised of sequential letters and numbers.
Example:
CharList : String = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';

I wish to go through it like addition so to speak. What I mean by this would be easier to explain through example.

'aaa' --> 'aab' --> 'aac' ... 'aa0' --> 'aba' --> 'abb' --> 'abc' ... 'ab0' --> 'aca' ... and so on.

The 'aaa', or starting point would come from CharList[1]. I am hoping that this can by dynamic so that any "CharList" of any length can be used.

I am going to work on this on my own but am wishing for other examples on how this can be accomplished. Points go to the most innovative and fastest routine =).
Avatar of kretzschmar
kretzschmar
Flag of Germany image

long time ago  . . . from my paq, may not the fastest

well, my version (sorry about the coding style)

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Memo1: TMemo;
    Edit2: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


function inc_integerarray(var IntArr : Array of Integer; OverflowAt, ResetTo : Integer) : boolean;
var
  isOverflow : boolean;
  i : integer;
begin
  isOverflow := true;
  for i := high(IntArr) downto low(IntArr) do
  begin
    if isOverflow then
    begin
      Inc(IntArr[i]);
      if IntArr[i] > OverFlowAt then
        IntArr[i] := ResetTo
      else
        isOverflow := false;
    end;
  end;
  result := isOverflow;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  combilength,i,j : integer;
  digitcounters : array of integer;
  validchars : string;
  validlen : integer;
  s : string;
  TheEnd : Boolean;

begin
  memo1.lines.clear;
  combilength := strtoint(edit2.text);
  validchars := edit1.Text;
  validlen := length(edit1.Text);
  for j := 1 to combilength do
  begin
    setlength(digitcounters,j);
    TheEnd := false;
    //reinit
    for i := 0 to high(digitcounters) do digitcounters[i] := 1;
    while not TheEnd do
    begin
      s := '';
      for i := 0 to high(digitcounters) do
        s := s + validchars[digitcounters[i]];
      memo1.Lines.Add(s);
      TheEnd := inc_integerarray(digitcounters,validlen,1);
    end;
  end;
  showmessage(inttostr(memo1.lines.Count)+' possible combinations');
end;

end.

meikl ;-)
My example does not include leading zeros (in your case 'a' s). What you are looking at is a base 62 number.  counting goes from single digit a-z, A-Z, 1-9, 0... then b followed by all of those.  since a represents 0 it is there in all of the original numbers, just not shown redundantly.  If you would like me to change the routine to handle a certain number of leading zeros (a's) instead, let me know.  I placed a TMemo, a TButton, and a TTimer on a form and attached the associated events.  The button toggles the timer on and off.  The timer result adds the converted integer to the memo and increments the timer.  The GetCount method is called by the Count property to automatically translate the integer into your number format.

Let me know if you need more.
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;
 
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Edit1: TEdit;
    Button1: TButton;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
    fCounter : integer;
    function GetCount: string;
  public
    { Public declarations }
    property Count : string read GetCount;
  end;
 
const
  BaseChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  Timer1.Enabled := not Timer1.Enabled;
end;
 
function TForm1.GetCount: string;
var
  Base : byte;
  Val : integer;
  Digit : byte;
  Line : string;
 
begin
  Base := Length(BaseChars);
  Val := fCounter;
  Line := '';
 
  repeat
    Digit := Val mod Base;
    Line := BaseChars[Digit + 1] + Line;
    Val := Val div Base;
  until Val = 0;
  Result := Line;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Memo1.Lines.Add(Count);
  inc(fCounter);
end;
 
end.

Open in new window

Avatar of ThievingSix

ASKER

@kretzschmar: Works great, although it takes days to complete.

@developmentguru: Fast, but it goes from 'zz' to 'baa' in a base a..z. Instead of 'zz' to 'aaa'.
as said, may not the fastest :-))

well, if you left out the output, then would itr be a bit faster, and of course, can be optimized

meikl ;-)
ASKER CERTIFIED SOLUTION
Avatar of kretzschmar
kretzschmar
Flag of Germany image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
 if a is your 0 then counting would react exactly as mine does.  It just does not include the leading 0's (a's).  If you left pad the result of mine with a's (how ever many you want) then the result is exactly what you are looking for.  in general you write 0 as 0 not 000.  This is all the difference you are seeing.  In this case zz is actually azz.  The next logical step is baa.  If you want to see it make more sense then put the 0123456789 as the first characters, not the last.  Then you will see the output you are expecting.  Either way, the output is correct.  If you don't believe me, try putting the digits first in the string as I suggested and you will see it.  I thought that was wrong at first too, but it is correct.  So, you have two choices.  1) Change the routine to left pad a's on the result or 2) change the order of the digits so you can see the results making sense.

  Let me know if you need more.