随机排列一个List
随机排列一个List
什么是在C#中随机排序通用列表的最佳方法?我有一个有限的75个数字的列表,我想为它们分配一个随机顺序,以便在类似于彩票的应用程序中进行抽取。
admin 更改状态以发布 2023年5月22日
使用基于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; } }
使用方法:
Listproducts = 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; } } } }