【问题标题】:Shuffle List<T> [duplicate]随机播放列表<T> [重复]
【发布时间】:2010-02-20 04:16:00
【问题描述】:

可能重复:
Randomize a List<T> in C#

我有一个包含数千个 FilePath 到音频文件位置的列表,我想知道哪种方法是“打乱”列表的最有效方式?

非常感谢任何帮助:)

谢谢

【问题讨论】:

  • 您真的想要最有效的解决方案,还是想要可接受的有效解决方案?因为有些算法比 Fischer-Yates 提供的更高效的算法让你愿意放弃某些好的属性,比如缺乏偏见。 (并不是说下面实施的 Fischer-Yates 是公正的;它有很大的偏见。)
  • @Eric:Fischer-Yates 公正的。正如您所指出的,下面给出的实现是不正确的。当然,如果您愿意有偏见,还有更有效的实现。例如,完全什么都不做。我真的不明白你的意思。 OP 没有指定任何内容,假设他们正在寻找统一的洗牌是合理的(IMO)。
  • 那我会通过解决不同的问题来解决你的问题。为什么你必须产生 50 万个文件的洗牌?用户永远不会进入随机播放中的最后一个文件,即使他们连续几个月每天都坐在那里点击“下一个”。也就是说,为什么要预先计算整个打乱顺序?随机选择几百个(无需更换)并称其为好。这不仅要更快,而且比分配一个包含 50 万个文件名的数组并改组整个数组的内存效率要高得多。
  • @j-t-s:同意 Eric 的观点:尝试事先对如此大的文件进行洗牌似乎毫无意义(而且效率很低)。一个与 Eric 不同的建议:您可以尝试保留一个包含 10 个(或 50 个)最后播放文件的列表。对于下一个文件,您可以生成一个随机数/文件(从 1 到 1/2 百万),如果它在最后播放的 10 个(或 50 个)中,请尝试再次获取一个随机数。对于所有实际目的,这应该足够了。

标签: c# list shuffle


【解决方案1】:

Fisher-Yates Shuffle 或者也称为 Knuth shuffle。

【讨论】:

  • ...这是 O(n),所以没有比这更好的了。
  • ...我只是赞成你,因为我喜欢你的回答 :) 不知道为什么它被否决了?
  • 顺便说一句,为了更快地洗牌,我建议你洗牌一个整数列表/数组(使用你选择的任何方法),并使用这个洗牌的列表/数组作为文件名列表的索引。交换文件名可能会成为瓶颈。
【解决方案2】:

这是 Fischer-Yates/Knuth shuffle 的简单(但有效)实现:

Random rnd = new Random();
for (int i = files.Length; i > 1; i--) {
  int pos = rnd.Next(i);
  var x = files[i - 1];
  files[i - 1] = files[pos];
  files[pos] = x;
}

或略有不同:

Random rnd = new Random();
for (int i = 1; i < files.Length; i++) {
  int pos = rnd.Next(i + 1);
  var x = files[i];
  files[i] = files[pos];
  files[pos] = x;
}

由于这是一个 O(n) 操作,它是最有效的洗牌列表的方法。由于列表中的所有项目都必须有机会移动,因此无法比 O(n) 更有效地打乱列表。

我使用这种方法和当前接受的答案 (LINQ OrderBy) 将一百万个项目每一个洗牌一千次,进行了一个小型性能测试,这大约快了 15 倍 (!)。

【讨论】:

  • 您将渐近界与效率混淆了。效率定义为完成每单位工作所消耗的资源。渐近界描述了消耗的资源如何随着问题大小的增加而增加。 System.String 类中的“在长度为 n 的字符串中查找长度为 m 的子字符串”算法是 O(nm),但它在 效率更高 >典型问题,而不是我们可以实现的 O(n+m) 算法。要计算效率,您必须考虑可能的情况,而不是渐近边界。
  • 我还注意到您对 Fischer-Yates 的实施存在偏见;它不会以相同的可能性产生所有可能的洗牌。对于音乐洗牌算法来说,这可能不是问题,但如果你用它来洗牌玩扑克游戏,就会出现问题;有了我的手,我可以很快确定其他人手中的东西。
  • @Eric:你为什么认为实现有偏差?它使每个项目都有相同的机会出现在列表中的每个位置。此外,我已经通过数百万次随机播放验证了实现,并且没有明显的偏差。
  • 设 x 为 Random 产生的可能随机订单数。设 y 是洗牌的可能排序数。我想你会发现,如果你计算出 x 和 y 是什么,在你的实现中 x 比 y 小得多,因此 shuffle 是有偏差的。
  • @Guffa:对不起,我误读了 Eric 的评论。我只想说这不是 Fischer Yates。至于偏差问题:正如您已经实现的那样,我们可以证明如果随机生成器是统一的,那么您产生的随机播放是统一的(或“无偏差”)。很抱歉造成混乱。
【解决方案3】:

myList.OrderBy(Guid.NewGuid())

【讨论】:

  • 一些 GUID 生成算法生成单调值,因此这可能不会给出随机结果。但是,使用其他随机源(可能是随机的)的类似方法会起作用。
【解决方案4】:

我将来自 this question 的 Jon Skeet 的解决方案添加到我的扩展库中。我实现的方法既采用外部随机数生成器,又使用默认实现(随机)创建一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-23
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多