Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Randomize multiple Stringlists

I want to randomize a number of string lists.

The string lists all contain the same number of items, and I wish to apply the same shuffle to each list. So if List1[0] is swapped with List1[7], then I want to swap List2[0] with List2[7], and so on for all the lists.

like image 963
Craig Avatar asked Feb 17 '26 08:02

Craig


1 Answers

I'm going to consider the case where you have two lists. I'll leave it up to you to generalise the ideas to handle more than two lists. The key understanding is best gained using the most simple case where there are two lists.

I would solve the problem like this:

  1. Generating a permutation of the integers 0, 1, ... N-1. Use the Fisher–Yates shuffle to achieve this.
  2. Using that permutation to shuffle both lists.

The key is to use the same permutation to shuffle both lists.

type
  TIntegerArray = array of Integer;

procedure Swap(var i1, i2: Integer); overload;
var
  tmp: Integer;
begin
  tmp := i1;
  i1 := i2;
  i2 := tmp;
end;

function GeneratePermutation(Count: Integer): TIntegerArray;
//Fisher-Yates shuffle
var
  i, j: Integer;
begin
  SetLength(Result, Count);
  for i := 0 to Count-1 do
    Result[i] := i;
  for i := Count-1 downto 1 do begin
    j := Random(i+1);
    Swap(Result[i], Result[j]);
  end;
end;

procedure ApplyPermutation(List: TStringList; 
  const Permutation: TIntegerArray);
var
  i: Integer;
  Temp: TStringList;
begin
  Assert(List.Count=Length(Permutation));
  Temp := TStringList.Create;
  try
    Temp.Assign(List);
    for i := 0 to List.Count-1 do
      List[i] := Temp[Permutation[i]];
  finally
    Temp.Free;
  end;
end;

And then you can apply to your situation like this:

Permutation := GeneratePermutation(List1.Count);
Apply(List1, Permutation);
Apply(List2, Permutation);

This is an exceedingly general solution that can be extended to more than two lists, and can be applied to other data types. If you want a very short and simple dedicated routine then you can do it like this:

procedure PermuteListsInTandem(List1, List2: TStringList);
var
  i, j: Integer;
begin
  Assert(List1.Count=List2.Count);
  for i := List1.Count-1 downto 1 do begin
    j := Random(i+1);
    List1.Exchange(i, j);
    List2.Exchange(i, j);
  end;
end;

I'm struggling to think of a good name for this procedure. Can anyone help me out by offering something better?

like image 167
David Heffernan Avatar answered Feb 20 '26 02:02

David Heffernan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!