3

我想随机化一些字符串列表。

字符串列表都包含相同数量的项目,我希望对每个列表应用相同的随机播放。因此,如果List1[0]与 交换List1[7],那么我想与所有列表交换List2[0]List2[7]依此类推。

4

1 回答 1

3

我将考虑您有两个列表的情况。我将由您来概括处理两个以上列表的想法。使用有两个列表的最简单的情况可以最好地获得关键的理解。

我会这样解决问题:

  1. 生成整数 0, 1, ... N-1 的排列。使用Fisher-Yates 洗牌来实现这一点。
  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);

这是一个非常通用的解决方案,可以扩展到两个以上的列表,并且可以应用于其他数据类型。如果您想要一个非常简短且简单的专用例程,那么您可以这样做:

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 回答