【问题标题】:Shuffle list of strings consistently一致地随机播放字符串列表
【发布时间】:2017-08-16 05:20:27
【问题描述】:

使用 C# 6,我有一个按字母顺序排列的名称列表:

List<String> names = getAlphabeticallyOrderedNames();

我需要改组名称,但我希望每次都得到相同的结果。所以我不能使用:

List<String> shuffledNames = names.OrderBy(x => Guid.NewGuid());

然后我尝试了类似的方法:

List<String> shuffledNames = names.OrderBy(x => "d2fda3b5-4089-43f9-ba02-f68d138dee49");

或者

List<String> shuffledNames = names.OrderBy(x => Int32.MaxValue);

但是名字并没有被洗牌……

我该如何解决这个问题?

【问题讨论】:

  • 我敢打赌,使用带有恒定种子的 Random 随机播放。
  • 使用来自this answer的洗牌器,但使用带有种子的Random构造函数的重载,并且每次都使用相同的种子。
  • .OrderBy(x => Guid.NewGuid()); 我认为这是一个可怕的 hack,用于 SQL 或在极少数情况下......
  • @xanatos 在这种情况下我没有在 SQL 中使用,但有时我需要在 SQL 中使用它

标签: c#


【解决方案1】:

你可以使用标准的shuffle算法,比如the one from this answer

适当修改以添加种子参数,它看起来像这样:

public static void Shuffle<T>(IList<T> list, int seed)
{
    var rng = new Random(seed);
    int n = list.Count;

    while (n > 1)
    {
        n--;
        int k = rng.Next(n + 1);
        T value = list[k];
        list[k] = list[n];
        list[n] = value;
    }
}

然后以可重复的方式洗牌,只需为每次重复洗牌指定相同的洗牌种子:

List<String> names = getAlphabeticallyOrderedNames();
int seed = 12345;
Shuffle(names, seed);

【讨论】:

  • 我正在寻找一个 IEnumerable 扩展而不是一个 IList 并且不更改源而是返回一个新的,以便它像 OrderBy 一样工作。我添加了更新,一个基于您的代码,另一个使用 yield。你认为哪一个更好?
  • @MiguelMoura 我看到更新 3 与this approach 基本相同。我会和那个一起去的。它在算法上也与我上面发布的 shuffle 算法相同。
  • 我做了一些单元测试,更新 3 似乎工作正常......这里是:rextester.com/YMQP20157
  • @MiguelMoura 是的,我认为你应该这样做!
【解决方案2】:

使用 Yield 并将种子值作为参数的可枚举扩展 (Online Example):

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Int32? seed = null) {

  List<T> buffer = source.ToList();

  Random random = seed.HasValue ? new Random(seed.Value) : new Random();

  Int32 count = buffer.Count;

  for (Int32 i = 0; i < count; i++) {          
    Int32 j = random.Next(i, count);
    yield return buffer[j];          
    buffer[j] = buffer[i];
  }

}

【讨论】:

    【解决方案3】:

    尝试按哈希值排序

    var shuffled = names.OrderBy(n=>n.GetHashCode());
    

    【讨论】:

    • 请注意,字符串的哈希值是不固定的...app.config/web.config 中有一个选项可以随机化“种子”。
    • 这没问题,除非 OP 想要保证每次运行应用程序的顺序相同。来自 MSDN:"The hash code itself is not guaranteed to be stable. Hash codes for identical strings can differ across versions of the .NET Framework and across platforms (such as 32-bit and 64-bit) for a single version of the .NET Framework. In some cases, they can even differ by application domain. "
    • 我确实想保证每次运行应用程序的顺序相同
    • 哈希不是随机的,并且会随着程序的每次新执行而发生变化。
    猜你喜欢
    • 2020-11-23
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    • 1970-01-01
    • 2023-01-23
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    相关资源
    最近更新 更多