如果你有这样的事情:
public class Tile
{
public int Number {get;set;}
...
}
你可以这样做:
var numbers = Enumerable
.Range(1, tilesList.Count) // generates list of sequential numbers
.OrderBy(x => Guid.NewGuid()) // shuffles the list
.ToList();
for (int i = 0; i < tiles.Count; i++)
{
tile[i].Number = numbers[i];
}
我知道,Guid 不是 Random 的替代方案,但它应该适合这种情况。
更新:只要答案被否决,我就编写了简单的测试,以检查 Guid 是否不可用于洗牌数组:
var larger = 0;
var smaller = 0;
var start = DateTime.Now;
var guid = Guid.NewGuid();
for (int i = 0; i < 10000000; i++)
{
var nextGuid = Guid.NewGuid();
if (nextGuid.CompareTo(guid) < 0)
{
larger++;
}
else
{
smaller++;
}
guid = nextGuid;
}
Console.WriteLine("larger: {0}", larger);
Console.WriteLine("smaller: {0}", smaller);
Console.WriteLine("took seconds: {0}", DateTime.Now - start);
Console.ReadKey();
它的作用是计算下一个 guid 比当前小多少倍,以及大多少倍。在完美的情况下,应该有相同数量的较大和较小的下一个 guid,这表明这两个事件(当前 guid 和下一个 guid)是独立的。还测量了时间,以确保它不会太慢。
并得到以下结果(有 1000 万个 guid):
更大:5000168
较小:4999832
花了几秒钟:00:00:01.1980686
另一个测试是直接比较 Fisher-Yates 和 Guid 改组:
static void Main(string[] args)
{
var numbers = Enumerable.Range(1, 7).ToArray();
var originalNumbers = numbers.OrderBy(x => Guid.NewGuid()).ToList();
var foundAfterListUsingGuid = new List<int>();
var foundAfterListUsingShuffle = new List<int>();
for (int i = 0; i < 100; i++)
{
var foundAfter = 0;
while (!originalNumbers.SequenceEqual(numbers.OrderBy(x => Guid.NewGuid())))
{
foundAfter++;
}
foundAfterListUsingGuid.Add(foundAfter);
foundAfter = 0;
var shuffledNumbers = Enumerable.Range(1, 7).ToArray();
while (!originalNumbers.SequenceEqual(shuffledNumbers))
{
foundAfter++;
Shuffle(shuffledNumbers);
}
foundAfterListUsingShuffle.Add(foundAfter);
}
Console.WriteLine("Average matching order (Guid): {0}", foundAfterListUsingGuid.Average());
Console.WriteLine("Average matching order (Shuffle): {0}", foundAfterListUsingShuffle.Average());
Console.ReadKey();
}
static Random _random = new Random();
public static void Shuffle<T>(T[] array)
{
var random = _random;
for (int i = array.Length; i > 1; i--)
{
// Pick random element to swap.
int j = random.Next(i); // 0 <= j <= i-1
// Swap.
T tmp = array[j];
array[j] = array[i - 1];
array[i - 1] = tmp;
}
}
“直接比较”的意思是,我正在生成打乱的序列并尝试再次打乱以获得相同的序列,并假设我需要生成相同序列的尝试越多,随机性就越好(这不是必要的数学正确假设,我认为这是过于简单化了)。
因此,为减少错误而进行 1000 次迭代的小集合的结果是:
平均匹配顺序(Guid):5015.097
平均匹配顺序(Shuffle):4969.424
所以,如果我的指标是正确的,Guid 会更好地执行事件:)
经过 10000 次迭代,它们更接近了:
平均匹配顺序(Guid):5079.9283
平均匹配顺序(Shuffle):4940.749
所以在我看来,对于当前的使用情况(游戏中的随机房间号),向导是合适的解决方案。