Random List <T>

What is the best way to randomize the generic list order in C??To draw a number for lottery-type applications, I want to assign a limited set of 75 numbers to a random-order list.

#1st floor

Use based on Fisher-Yates shuffle Extension method for (I)List Random Sort :

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 criticized System.Random method to select candidates for an exchange.It's fast, but not as random as it should be.If you need more randomness, use the random number generator in System.Security.Cryptograph, as shown below:

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

On this blog On (WayBack Machine) Conduct Simple comparison.

Editor: Since writing this answer a few years ago, many people have commented or written to me pointing out a foolish flaw in my comparison.They are certainly right.If System.Random is used as expected, there are no problems.In the first example above, I instantiated the rng variable inside the Shuffle method, which asks if the method should be called repeatedly.Here is a fixed, complete example based on the very useful comments on SO received today from @weston.

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

#2nd floor

This is an efficient Shuffler that returns a byte array of mixed values.It won't shuffle more cards than it needs.You can restart from where you previously interrupted.My actual implementation (not shown) is a MEF component that allows the user to specify a replacement shuffler.

    public byte[] Shuffle(byte[] array, int start, int count)
    {
        int n = array.Length - start;
        byte[] shuffled = new byte[count];
        for(int i = 0; i < count; i++, start++)
        {
            int k = UniformRandomGenerator.Next(n--) + start;
            shuffled[i] = array[k];
            array[k] = array[start];
            array[start] = shuffled[i];
        }
        return shuffled;
    }

`

#3rd floor

This is a thread-safe approach:

public static class EnumerableExtension
{
    private static Random globalRng = new Random();

    [ThreadStatic]
    private static Random _rng;

    private static Random rng 
    {
        get
        {
            if (_rng == null)
            {
                int seed;
                lock (globalRng)
                {
                    seed = globalRng.Next();
                }
                _rng = new Random(seed);
             }
             return _rng;
         }
    }

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items)
    {
        return items.OrderBy (i => rng.Next());
    }
}

#4th floor

If you don't mind using two Lists, this may be the easiest method, but it may not be the most efficient or unpredictable:

List<int> xList = new List<int>() { 1, 2, 3, 4, 5 };
List<int> deck = new List<int>();

foreach (int xInt in xList)
    deck.Insert(random.Next(0, deck.Count + 1), xInt);

#5th floor

I'm surprised at all the awkward versions of this simple algorithm.Fisher-Yates (or Knuth shuffling) is tricky, but compact.Why is it tricky?Because you need to be aware that the random number generator r(a,b) returns values that B contains or excludes.I also edited Wikipedia's description, So people don't blindly follow pseudo-code and cause undetectable errors.For.Net, Random.Next(a,b) returns a number that does not include b, so it's easy to do this in C #/.Methods implemented in Net:

public static void Shuffle<T>(this IList<T> list, Random rnd)
{
    for(var i=list.Count; i > 0; i--)
        list.Swap(0, rnd.Next(0, i));
}

public static void Swap<T>(this IList<T> list, int i, int j)
{
    var temp = list[i];
    list[i] = list[j];
    list[j] = temp;
}

Try this code .

Posted by timmybuck on Wed, 18 Dec 2019 23:01:29 -0800