随机排列一个List

17 浏览
0 Comments

随机排列一个List

什么是在C#中随机排序通用列表的最佳方法?我有一个有限的75个数字的列表,我想为它们分配一个随机顺序,以便在类似于彩票的应用程序中进行抽取。

admin 更改状态以发布 2023年5月22日
0
0 Comments

如果我们只需要按完全随机的顺序洗牌项目(仅仅是为了在列表中混合项目),我更喜欢这个简单而有效的代码,它通过guid对项目进行排序......\n

var shuffledcards = cards.OrderBy(a => Guid.NewGuid()).ToList();

\n


\n如评论中所指出的,GUID不能保证是随机的,因此我们应该使用真正的随机数生成器: \n

private static Random rng = new Random();
...
var shuffledcards = cards.OrderBy(a => rng.Next()).ToList();

0
0 Comments

使用基于Fisher-Yates洗牌的扩展方法来随机排序任何(I)List:

private static Random rng = new Random();  
public static void Shuffle(this IList list)  
{  
    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 products = GetProducts();
products.Shuffle();


上面的代码使用了备受批评的System.Random方法来选择交换候选项。它很快,但不像应该的那样随机。如果您需要更好的随机性质来随机播放,请像这样使用System.Security.Cryptography中的随机数生成器:

using System.Security.Cryptography;
...
public static void Shuffle(this IList list)
{
    RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
    int n = list.Count;
    while (n > 1)
    {
        byte[] box = new byte[1];
        do provider.GetBytes(box);
        while (!(box[0] < n * (Byte.MaxValue / n)));
        int k = (box[0] % n);
        n--;
        T value = list[k];
        list[k] = list[n];
        list[n] = value;
    }
}


在这个博客中可以找到一个简单的比较 (WayBack机器)。

编辑:自从几年前写下这个答案以来,许多人已经评论或写信给我,指出了我的比较中的大傻瓜缺陷。他们当然是正确的。如果按照它的预期使用System.Random没有问题。在我的第一个示例中,我实例化了Shuffle方法内的rng变量,如果要重复调用该方法,这是在寻求麻烦。下面是一个修复的、完整的示例,基于@weston今天在SO上收到的一条非常有用的评论。

Program.cs:

using System;
using System.Collections.Generic;
using System.Threading;
namespace SimpleLottery
{
  class Program
  {
    private static void Main(string[] args)
    {
      var numbers = new List(Enumerable.Range(1, 75));
      numbers.Shuffle();
      Console.WriteLine("The winning numbers are: {0}", string.Join(",  ", numbers.GetRange(0, 5)));
    }
  }
  public static class ThreadSafeRandom
  {
      [ThreadStatic] private static Random Local;
      public static Random ThisThreadsRandom
      {
          get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
      }
  }
  static class MyExtensions
  {
    public static void Shuffle(this IList list)
    {
      int n = list.Count;
      while (n > 1)
      {
        n--;
        int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
        T value = list[k];
        list[k] = list[n];
        list[n] = value;
      }
    }
  }
}

0