【问题标题】:Randomize StringList随机化字符串列表
【发布时间】:2012-12-22 20:10:57
【问题描述】:

我怎样才能像这个在线工具一样随机化 StringList 中的字符串。如果有人熟悉它,请检查:http://textmechanic.co/Randomize-List.html

【问题讨论】:

标签: delphi delphi-xe2


【解决方案1】:

执行随机播放的一种常见算法是Fisher-Yates 随机播放。这会生成均匀分布的排列。

要在 Delphi TStrings 对象上实现,您可以使用:

procedure Shuffle(Strings: TStrings);
var
  i: Integer;
begin
  for i := Strings.Count-1 downto 1 do 
    Strings.Exchange(i, Random(i+1));
end;

现在,虽然理论上这将生成均匀分布的排列,但实际性能在很大程度上取决于随机数生成器的质量。这在 Knuth 的计算机编程艺术,第 2 卷,第 3.4.2 节,算法 P 中进行了讨论。

进一步阅读:

【讨论】:

  • 我们不能使用 RandomRange 吗?
  • 是的,桑托斯,但何必呢? Random(i+1) 等价于 RandomRange(0, i)。
  • 回复的是@Rob?而且我不明白你为什么对那些尽力做好事并一路帮助你的人采取讽刺的语气。
  • @DavidHeffernan 是的,但是您提供的解决方案几乎与 GolezTrol 完全相同:)
  • 一点也不。 Golez 的代码有偏差。一些排列的选择概率高于其他排列。我怀疑你不想那样。
【解决方案2】:

只需遍历字符串列表并给每个项目一个不同的随机位置:

for i := StringList.Count - 1 downto 1 do
  StringList.Exchange(i, Random(i+1));

[编辑] 稍微改变循环以使洗牌均匀。

【讨论】:

  • 是的,真正的洗牌 :) 也是最理智的一个。
  • 这个答案演示了维基百科"implementation errors"部分中讨论的Fisher-Yates错误之一。虽然它仍然会产生一个洗牌的结果,这是所有问题,但它不是一个统一的洗牌算法。 RNG 的质量与该问题无关。
  • @RobKennedy 好的。很高兴知道,您指出的解释非常清楚。我稍微改变了循环。使用 downto,因为它使循环更简单。 +1 用于防止意外执行 Sattolo 算法。
  • 所以我删除了我所有的 cmets,因为它们不再适用于您的答案
【解决方案3】:

要随机化 TStrings,请使用 随机结果值TComparer 创建一个比较器,并用它对 TStrings 进行排序。

/// The Comparer
TMyShuffleComparer= class(TComparer<string>)
public
  function Compare(const Left, Right: string): Integer; override;
end;

/// The randomizer 
function TMyShuffleComparer.Compare(const Left, Right: TCard): Integer;
begin
  // To sort, get a random number for compare result
  Result := Random(100) - 50;
end;

/// How to call the comparer
procedure TMyStrings.Shuffle;
begin
 Sort(TMyShuffleComparer.Create);
end;

或直接调用:

  /// Shuffle
  MyString.Sort(TMyShuffleComparer.Create);

【讨论】:

  • -1 排序比较函数需要定义一个总顺序。这没有。这简直是​​个可怕的主意。我建议你删除答案。阅读此内容,例如:blogs.msdn.com/b/oldnewthing/archive/2003/10/23/55408.aspx
  • 比较函数不一致会导致非终止排序函数和缓冲区溢出。它们不是随机排列列表的方式。
  • 虽然可以使用排序算法来洗牌,但这不是如何做到的。即使你做对了,你的代码也比 Fisher-Yates 慢得多。
  • 我根据您的评论测试了它,现在我明白了我在比较器上的错误。试图回复答案,我已经修复了自己的错误;)
  • 这是一种新奇的想法,但是,正如@Rob所说,你的比较函数必须是deterministic(忽略SQL风格),否则你最终会得到结果列表洗得很差。
猜你喜欢
  • 2013-10-14
  • 2016-03-29
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2016-06-21
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
相关资源
最近更新 更多