且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

随机列表< T>

更新时间:2022-05-15 15:32:04

随机播放任何(I)名单与基于的Fisher-Yates洗牌

Shuffle any (I)List with an extension method based on the Fisher-Yates shuffle:

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();

上面的code采用了备受诟病的System.Random方法来选择调剂的考生。它速度快,但不是随机因为它应该是。如果你需要的随机性在洗牌更好的品质,使用随机数发生器System.Security.Cryptography像这样:

The code above uses the much criticised System.Random method to select swap candidates. It's fast but not as random as it should be. If you need a better quality of randomness in your shuffles use the random number generator in System.Security.Cryptography like so:

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;
    }
}

一个简单的比较,请访问:http://thegrenade.blogspot.com/2010/02/when-random-is-too-consistent.html

A simple comparison is available at: http://thegrenade.blogspot.com/2010/02/when-random-is-too-consistent.html

编辑:既然写这个答案一对夫妇几年前,很多人都评论或写信给我,在我的比较指出大傻缺陷。他们当然是对的。如果它在它的目的的方式使用有什么错System.Random。在我上面的第一例子,我实例化Shuffle的方法,这是自寻烦恼,如果该方法将被反复调用内部的RNG变量。下面是今天收到来自@weston这里SO基于一个真正有用的评论固定的,完整的例子。

Since writing this answer a couple years back, many people have commented or written to me, to point out the big silly flaw in my comparison. They are of course right. There's nothing wrong with System.Random if it's used in the way it was intended. In my first example above, I instantiate the rng variable inside of the Shuffle method, which is asking for trouble if the method is going to be called repeatedly. Below is a fixed, full example based on a really useful comment received today from @weston here on SO.

Program.cs的:

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;
      }
    }
  }
}