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


当前回答

 public Deck(IEnumerable<Card> initialCards) 
    {
    cards = new List<Card>(initialCards);
    public void Shuffle() 
     }
    {
        List<Card> NewCards = new List<Card>();
        while (cards.Count > 0) 
        {
            int CardToMove = random.Next(cards.Count);
            NewCards.Add(cards[CardToMove]);
            cards.RemoveAt(CardToMove);
        }
        cards = NewCards;
    }

public IEnumerable<string> GetCardNames() 

{
    string[] CardNames = new string[cards.Count];
    for (int i = 0; i < cards.Count; i++)
    CardNames[i] = cards[i].Name;
    return CardNames;
}

Deck deck1;
Deck deck2;
Random random = new Random();

public Form1() 
{

InitializeComponent();
ResetDeck(1);
ResetDeck(2);
RedrawDeck(1);
 RedrawDeck(2);

}



 private void ResetDeck(int deckNumber) 
    {
    if (deckNumber == 1) 
{
      int numberOfCards = random.Next(1, 11);
      deck1 = new Deck(new Card[] { });
      for (int i = 0; i < numberOfCards; i++)
           deck1.Add(new Card((Suits)random.Next(4),(Values)random.Next(1, 14)));
       deck1.Sort();
}


   else
    deck2 = new Deck();
 }

private void reset1_Click(object sender, EventArgs e) {
ResetDeck(1);
RedrawDeck(1);

}

private void shuffle1_Click(object sender, EventArgs e) 
{
    deck1.Shuffle();
    RedrawDeck(1);

}

private void moveToDeck1_Click(object sender, EventArgs e) 
{

    if (listBox2.SelectedIndex >= 0)
    if (deck2.Count > 0) {
    deck1.Add(deck2.Deal(listBox2.SelectedIndex));

}

    RedrawDeck(1);
    RedrawDeck(2);

}

其他回答

对已接受答案的简单修改,返回一个新的列表,而不是原地工作,并像许多其他Linq方法一样接受更通用的IEnumerable<T>。

private static Random rng = new Random();

/// <summary>
/// Returns a new list where the elements are randomly shuffled.
/// Based on the Fisher-Yates shuffle, which has O(n) complexity.
/// </summary>
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> list) {
    var source = list.ToList();
    int n = source.Count;
    var shuffled = new List<T>(n);
    shuffled.AddRange(source);
    while (n > 1) {
        n--;
        int k = rng.Next(n + 1);
        T value = shuffled[k];
        shuffled[k] = shuffled[n];
        shuffled[n] = value;
    }
    return shuffled;
}

可以使用morelinq包中的Shuffle扩展方法,它适用于IEnumerables

安装包morelinq

using MoreLinq;
...    
var randomized = list.Shuffle();
private List<GameObject> ShuffleList(List<GameObject> ActualList) {


    List<GameObject> newList = ActualList;
    List<GameObject> outList = new List<GameObject>();

    int count = newList.Count;

    while (newList.Count > 0) {

        int rando = Random.Range(0, newList.Count);

        outList.Add(newList[rando]);

        newList.RemoveAt(rando);

     

    }

    return (outList);

}

用法:

List<GameObject> GetShuffle = ShuffleList(ActualList);

解决这类问题的一个非常简单的方法是在列表中使用一些随机的元素交换。

在伪代码中是这样的:

do 
    r1 = randomPositionInList()
    r2 = randomPositionInList()
    swap elements at index r1 and index r2 
for a certain number of times

这是我最喜欢的shuffle方法,当不需要修改原始的时候。它是Fisher-Yates“由内到外”算法的变体,适用于任何可枚举序列(源的长度不需要从一开始就知道)。

public static IList<T> NextList<T>(this Random r, IEnumerable<T> source)
{
  var list = new List<T>();
  foreach (var item in source)
  {
    var i = r.Next(list.Count + 1);
    if (i == list.Count)
    {
      list.Add(item);
    }
    else
    {
      var temp = list[i];
      list[i] = item;
      list.Add(temp);
    }
  }
  return list;
}

该算法还可以通过分配一个从0到length - 1的范围来实现,并通过将随机选择的索引与最后一个索引交换来随机耗尽索引,直到所有索引都被选中一次。上面的代码完成了完全相同的事情,但没有额外的分配。非常简洁。

With regards to the Random class it's a general purpose number generator (and If I was running a lottery I'd consider using something different). It also relies on a time based seed value by default. A small alleviation of the problem is to seed the Random class with the RNGCryptoServiceProvider or you could use the RNGCryptoServiceProvider in a method similar to this (see below) to generate uniformly chosen random double floating point values but running a lottery pretty much requires understanding randomness and the nature of the randomness source.

var bytes = new byte[8];
_secureRng.GetBytes(bytes);
var v = BitConverter.ToUInt64(bytes, 0);
return (double)v / ((double)ulong.MaxValue + 1);

生成随机双精度(仅在0和1之间)的目的是用于扩展到整数解。如果你需要从一个基于随机双x的列表中选择一个东西,它总是0 <= x && x < 1是很简单的。

return list[(int)(x * list.Count)];

享受吧!