いくつかの文字列リストをランダム化したい。
文字列リストにはすべて同じ数のアイテムが含まれているので、各リストに同じシャッフルを適用したいと思います。したがって、がと交換された場合List1[0]
は、すべてのリストについて、と交換しList1[7]
たいと思います。List2[0]
List2[7]
リストが 2 つある場合を考えてみましょう。3 つ以上のリストを処理するためのアイデアを一般化することは、皆さんに任せます。鍵となる理解は、2 つのリストがある最も単純なケースを使用することで最もよく理解できます。
私は次のように問題を解決します:
重要なのは、同じ順列を使用して両方のリストをシャッフルすることです。
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;
そして、次のように状況に適用できます。
Permutation := GeneratePermutation(List1.Count);
Apply(List1, Permutation);
Apply(List2, Permutation);
これは、2 つ以上のリストに拡張でき、他のデータ型にも適用できる非常に一般的なソリューションです。非常に短くシンプルな専用ルーチンが必要な場合は、次のように実行できます。
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;
この手順の適切な名前を考えるのに苦労しています。誰かがより良いものを提供することで私を助けることができますか?