随机播放任何
(I)List基于该扩展方法费雪耶茨洗牌:
private static Random rng = new Random();public static void Shuffle<T>(this IList<T> 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<Product> products = GetProducts();products.Shuffle();
上面的代码使用备受批评的System.Random方法来选择交换候选。它速度很快,但不如应有的随机。如果您需要更好的随机性,请使用System.Security.Cryptography中的随机数生成器,如下所示:
using System.Security.Cryptography;...public static void Shuffle<T>(this IList<T> 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
Machine)上可以进行简单的比较。
编辑:自从几年前写下这个答案以来,许多人向我发表评论或写信给我,指出我的比较中的一个愚蠢的缺陷。他们当然是对的。如果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<int>(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<T>(this IList<T> 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条)