在各种编程场景中,随机化泛型列表中元素的顺序是一种常见的操作。本文将介绍在C#中实现此目标的最佳方法。
最推荐的方法是使用Fisher-Yates洗牌算法,这是一种众所周知的列表随机化算法。要使用此方法,请定义一个扩展方法,如下所示:
<code class="language-csharp">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; } }</code>
使用方法:
<code class="language-csharp">List<Product> products = GetProducts(); products.Shuffle();</code>
虽然System.Random
效率很高,但它可能无法生成真正的随机序列。为了提高随机性,System.Security.Cryptography
库提供了一个更可靠的选项:
<code class="language-csharp">public static void Shuffle<T>(this IList<T> list) { using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider()) { int n = list.Count; while (n > 1) { byte[] box = new byte[1]; do provider.GetBytes(box); while (!(box[0] < (byte)((double)n / 256))); //确保生成的随机数在范围内 int k = (int)(box[0] * (n / 256.0)); T value = list[k]; list[k] = list[n - 1]; list[n - 1] = value; n--; } } }</code>
在多线程应用程序中使用Shuffle扩展方法时,务必确保线程安全。一个简单的解决方法是创建一个ThreadSafeRandom
的新实例:
<code class="language-csharp">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))); } } }</code>
将线程安全方法集成到Shuffle扩展方法中:
<code class="language-csharp">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; } }</code>
This revised answer provides clearer explanations, improves code readability (especially the RNGCryptoServiceProvider example), and addresses thread safety concerns more effectively. The image remains in its original format and location.
以上是如何在C#中有效地将通用列表改组?的详细内容。更多信息请关注PHP中文网其他相关文章!