Random Number into StringList

eNarc
eNarc used Ask the Experts™
on
Hi, I'm wanting to put Random Numbers into Stringlist though I don't want any duplicates and need to be in a random order within the stringlist.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
Use the code bellow, be carefull as it frees the stringlist at the end. It is just an example on how to do what you want...

procedure TForm1.Button2Click(Sender: TObject);
var
 i: Integer;
 s: TStringList;
begin
 Randomize;
 s := TStringList.Create;
 try
  i := RandomRange(1, 100); // put any range you want, if not use i := Random;
  if s.IndexOf(IntToStr(i)) = -1 then
   s.Append(IntToStr(i));
 finally
  s.Free;
 end;
end;
gskoczylasSenior Software Developer

Commented:
The twinsoft's algorithm is simple, but very inefficient. It is better to first generate a list of random values and then use it.

For example:

const
  ValuesCount = 1000;
var
  RandomValues:  array[1..ValuesCount] of Integer;
  n: Integer;
  StrList: TStringList;
begin
  Randomize;
  for n := 1 to ValuesCount do
    RandomValues[n] := RandomRange(1, 100);
  StrList := TStringList.Create;
  try
    for n := 1 to ValuesCount do
      StrList.Add(IntToStr(RandomValues[n]));
    ...
  finally
    StrList.Free;
  end { try-finally }
end;

Author

Commented:
I've tested your code gskoczylas and it brings back pretty much the same numbers and there can not be any duplicates.
Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Author

Commented:
I've just done another test, from 1000 entrys only 99 were unique.

Author

Commented:
I changed the

RandomValues[n] := RandomRange(1, 100);

to

RandomValues[n] := RandomRange(1, 1000);

and out of 1000 entries only 631 where unique, so thats failed.

I'm still interested in what you had in mind gskoczylas, would u like to elaborate more?

Author

Commented:
from looking at your code twinsoft, and from another question you've replied in, you posted this function.

function iFound(s:string):boolean;
begin
  Application.ProcessMessages;
  Result := SL1.IndexOf(s) <> -1;
end;

I found this to be very useful.

I then created this.

  repeat
    o:=inttostr(Random(1000));
    while not iFound(o) do
      SL1.Add(o);
  until (1000 = SL1.Count);

results 1001/1001/1001 perfect match. each one unique.

could I neaten and improve this code to work better and faster?

I'm aware of the case that the random has to match that of the SL1 that isn't found for a entry to be inserted which could mean that it be wasting allot of cycles in finding the answer.

is there a faster way? as it takes around 6mil ms to complete.
Commented:
Hi, you could change the code like this but the execution time won't change much...

  repeat
    o:=inttostr(Random(1000));
    if SL1.IndexOf(o) = -1 then
      SL1.Add(o);
  until (1000 = SL1.Count);

Author

Commented:
I've changed the code to be a lil different instead of accumulating them all at once, they are inserted by each click, making it if all clicked 1000 it would be all unique.

I may put if SL1.count=1000 then SL1.clear; and start all over again.

//repeat
  try
    repeat
      o:= inttostr(Random(1000));
    until not iFound(o);
  finally
    SL1.Add(o);
  end;
//until (1000 = SL1.Count);

The // will act like a filler of the SL1 and without individually.

both amount to being the same speed for individually accumulating and the filler, so which ever suits the user having no pause with a click or having a pause with each click though amounts to being the same speeds.

Author

Commented:
your right twinsoft, it doesn't speed up though it does neaten the code and uses less code and places it all nicely into 1 area.

Commented:
One more hint, if you don't want your UI to freeze when you enter a long loop inser this line inside the loop

Application.ProcessMessage;

This will not block your form from interacting with the user...

Author

Commented:
yep I put that into the function iFound.

function iFound(s:string):boolean;
begin
  Application.ProcessMessages;
  Result := SL1.IndexOf(s) <> -1;
end;

I like using Application.ProcessMessages
gskoczylasSenior Software Developer

Commented:
My previous code was not correct. Sorry!

Optimal solution depends on your priorities: either small and simple code or fast code.

If you prefer small and simple code, you can use twinsoft's code. This code is simple but slow because if almost all numbers are used then very often generated candidate already exists on the list.

If you prefer efficient (fast) code, you can use something like code attached to this message. This time I tested it.

program TestApp;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

const
  ValuesCount = 10000;

var
  Values: TStringList;
  Temp:   TStringList;
  i, j:   Integer;

begin
  try
    Randomize;
    Values := TStringList.Create;
    try
      Temp := TStringList.Create;
      try
        for i := 1 to ValuesCount do
          Temp.Add(IntToStr(i));
        for i := 1 to ValuesCount do
          begin
            j := Random(Temp.Count);
           Values.Add(Temp[j]);
           Temp.Delete(j);
          end { for i  };
      finally
        Temp.Free;
      end { try-finally };

      { processing "Values" }
      for  i := 0  to  Values.Count - 1  do
        write(Values[i]:10);
      Writeln; Write('Press [Enter] '); Readln;

      { Checking duplicates }
      j := 0;   // number of duplicates
      Values.Sort;
      for  i := 0  to  Values.Count - 2  do
        if  Values[i] = Values[i+1]  then
          begin
            Writeln('Value ', Values[i], ' is duplicated');
            Inc(j);
          end ;
      Writeln; Write('---> ', j, ' duplicate(s) has been found. Press [Enter] '); Readln;

    finally
      Values.Free;
    end { try-finally };
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

Open in new window

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial