3

いくつかの文字列リストをランダム化したい。

文字列リストにはすべて同じ数のアイテムが含まれているので、各リストに同じシャッフルを適用したいと思います。したがって、がと交換された場合List1[0]は、すべてのリストについて、と交換しList1[7]たいと思います。List2[0]List2[7]

4

1 に答える 1

3

リストが 2 つある場合を考えてみましょう。3 つ以上のリストを処理するためのアイデアを一般化することは、皆さんに任せます。鍵となる理解は、2 つのリストがある最も単純なケースを使用することで最もよく理解できます。

私は次のように問題を解決します:

  1. 整数 0、1、... N-1 の順列を生成します。これを達成するには、フィッシャー・イェーツ シャッフルを使用します。
  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;

この手順の適切な名前を考えるのに苦労しています。誰かがより良いものを提供することで私を助けることができますか?

于 2013-01-11T10:14:22.903 に答える