Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
291 views
in Technique[技术] by (71.8m points)

c# - 随机列表<T>(Randomize a List<T>)

What is the best way to randomize the order of a generic list in C#?

(在C#中随机化泛型列表顺序的最佳方法是什么?)

I've got a finite set of 75 numbers in a list I would like to assign a random order to, in order to draw them for a lottery type application.

(为了给彩票类型的应用程序绘制一个数字,我想分配一个随机顺序的列表中有75个数字的有限集合。)

  ask by mirezus translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

(使用基于Fisher-Yates shuffle的扩展方法对(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;  
    }  
}

Usage:

(用法:)

List<Product> products = GetProducts();
products.Shuffle();

The code above uses the much criticised System.Random method to select swap candidates.

(上面的代码使用备受批评的System.Random方法来选择交换候选。)

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:

(如果您需要更好的随机性,请使用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;
    }
}

A simple comparison is available at this blog (WayBack Machine).

(在此博客 (WayBack Machine)上可以进行简单的比较。)

Edit: 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.

(如果System.Random按预期方式使用,则没有任何问题。)

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.

(在上面的第一个示例中,我在Shuffle方法内部实例化了rng变量,该变量询问是否要重复调用该方法。)

Below is a fixed, full example based on a really useful comment received today from @weston here on SO.

(以下是一个固定的完整示例,该示例基于今天从@weston收到的关于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;
      }
    }
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...