在c#中随机化泛型列表顺序的最佳方法是什么?我在一个列表中有一个有限的75个数字集,我想随机分配一个顺序,以便为彩票类型的应用程序绘制它们。
当前回答
I'm bit surprised by all the clunky versions of this simple algorithm here. Fisher-Yates (or Knuth shuffle) is bit tricky but very compact. Why is it tricky? Because your need to pay attention to whether your random number generator r(a,b) returns value where b is inclusive or exclusive. I've also edited Wikipedia description so people don't blindly follow pseudocode there and create hard to detect bugs. For .Net, Random.Next(a,b) returns number exclusive of b so without further ado, here's how it can be implemented in C#/.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;
}
试试这段代码。
其他回答
解决这类问题的一个非常简单的方法是在列表中使用一些随机的元素交换。
在伪代码中是这样的:
do
r1 = randomPositionInList()
r2 = randomPositionInList()
swap elements at index r1 and index r2
for a certain number of times
如果我们只需要以完全随机的顺序洗牌项目(只是在一个列表中混合项目),我更喜欢这个简单而有效的代码,按guid排序项目…
var shuffledcards = cards.OrderBy(a => Guid.NewGuid()).ToList();
正如人们在评论中指出的那样,guid不能保证是随机的,所以我们应该使用真正的随机数生成器:
private static Random rng = new Random();
...
var shuffledcards = cards.OrderBy(a => rng.Next()).ToList();
您可以使用这个简单的扩展方法来实现这一点
public static class IEnumerableExtensions
{
public static IEnumerable<t> Randomize<t>(this IEnumerable<t> target)
{
Random r = new Random();
return target.OrderBy(x=>(r.Next()));
}
}
你可以通过下面的步骤来使用它
// use this on any collection that implements IEnumerable!
// List, Array, HashSet, Collection, etc
List<string> myList = new List<string> { "hello", "random", "world", "foo", "bar", "bat", "baz" };
foreach (string s in myList.Randomize())
{
Console.WriteLine(s);
}
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);
}
I'm bit surprised by all the clunky versions of this simple algorithm here. Fisher-Yates (or Knuth shuffle) is bit tricky but very compact. Why is it tricky? Because your need to pay attention to whether your random number generator r(a,b) returns value where b is inclusive or exclusive. I've also edited Wikipedia description so people don't blindly follow pseudocode there and create hard to detect bugs. For .Net, Random.Next(a,b) returns number exclusive of b so without further ado, here's how it can be implemented in C#/.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;
}
试试这段代码。