在c#中随机化泛型列表顺序的最佳方法是什么?我在一个列表中有一个有限的75个数字集,我想随机分配一个顺序,以便为彩票类型的应用程序绘制它们。


当前回答

这里是Fisher-Yates shuffle的实现,允许指定返回的元素数量;因此,在获取所需数量的元素之前,没有必要首先对整个集合进行排序。

交换元素的顺序与默认值相反;从第一个元素到最后一个元素,因此检索集合的一个子集与洗牌整个集合产生相同的(部分)序列:

collection.TakeRandom(5).SequenceEqual(collection.Shuffle().Take(5)); // true

该算法基于Durstenfeld在维基百科上的(现代)Fisher-Yates shuffle。

public static IList<T> TakeRandom<T>(this IEnumerable<T> collection, int count, Random random) => shuffle(collection, count, random);
public static IList<T> Shuffle<T>(this IEnumerable<T> collection, Random random) => shuffle(collection, null, random);
private static IList<T> shuffle<T>(IEnumerable<T> collection, int? take, Random random)
{
    var a = collection.ToArray();
    var n = a.Length;
    if (take <= 0 || take > n) throw new ArgumentException("Invalid number of elements to return.");
    var end = take ?? n;
    for (int i = 0; i < end; i++)
    {
        var j = random.Next(i, n);
        (a[i], a[j]) = (a[j], a[i]);
    }

    if (take.HasValue) return new ArraySegment<T>(a, 0, take.Value);
    return a;
}

其他回答

只是想建议使用IComparer<T>和List.Sort()的变体:

public class RandomIntComparer : IComparer<int>
{
    private readonly Random _random = new Random();
    
    public int Compare(int x, int y)
    {
        return _random.Next(-1, 2);
    }
}

用法:

list.Sort(new RandomIntComparer());

我通常使用:

var list = new List<T> ();
fillList (list);
var randomizedList = new List<T> ();
var rnd = new Random ();
while (list.Count != 0)
{
    var index = rnd.Next (0, list.Count);
    randomizedList.Add (list [index]);
    list.RemoveAt (index);
}

下面是一个高效的Shuffler,它返回一个字节数组的打乱值。它从来不会超过需要的次数。它可以从之前停止的地方重新启动。我的实际实现(未显示)是一个MEF组件,它允许用户指定替换洗牌器。

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

`

实现:

public static class ListExtensions
{
    public static void Shuffle<T>(this IList<T> list, Random random)
    {
        for (var i = list.Count - 1; i > 0; i--)
        {
            int indexToSwap = random.Next(i + 1);
            (list[indexToSwap], list[i]) = (list[i], list[indexToSwap]);
        }
    }
}

例子:

var random = new Random();
var array = new [] { 1, 2, 3 };
array.Shuffle(random);
foreach (var item in array) {
    Console.WriteLine(item);
}

.NET小提琴演示

我在网上找到了一个有趣的解决办法。

礼貌:https://improveandrepeat.com/2018/08/a-simple-way-to-shuffle-your-lists-in-c/

var shuffled = myList。OrderBy(x => Guid.NewGuid()).ToList();