无效的阵列洗牌器

时间:2010-10-30 03:52:29

标签: c# arrays random shuffle

我试图改组一个阵列,但我这样做的方式大约每五次一次。如果有人能解释为什么它不能正常工作并且可能提出调整,我将不胜感激。

private Button[] scrambleBoard(Button[] buttons)
{
    for (int x = 100 * buttons.Count(); x > 0; x--)
    {
        Random rand = new Random();
        int first = rand.Next(buttons.Count());
        int second = rand.Next(buttons.Count());


        Button temp = buttons[first];
        buttons[first] = buttons[second];
        buttons[second] = temp;
    }

    return buttons;
}

3 个答案:

答案 0 :(得分:3)

将以下行移到循环外:

Random rand = new Random();

System.Random使用的默认种子基于Environment.TickCount。在紧密循环中,滴答计数在连续迭代之间可能不会改变,因此它可能会一遍又一遍地使用相同的种子。因此,循环将重复交换相同的两个元素,直到滴答计数发生变化(在循环完成之前可能不会这样做)。要验证这是否是问题,您可以尝试在循环内添加Thread.Sleep(100)或类似内容;然后你应该能够看到shuffle正常工作(虽然非常缓慢)。

您还应该注意,排列数组的technique you're using 有偏见;不是每个排列都是同样可能的。您可能希望使用已知为无偏的混洗算法,例如Fisher-Yates shuffle

或者,您可以使用非常简单的技术进行随机播放。它效率稍低,但没有偏见:

var rand = new Random();
return buttons.OrderBy(button => rand.Next()).ToArray();

答案 1 :(得分:1)

问题是你在循环的每次迭代中创建了Random()对象。由于Random对象在初始化期间使用种子,因此您会发现大多数值都是相同的而不是随机的。

您可以通过在方法体外声明Random类为静态来解决问题。

private static Random rand = new Random();

private Button[] scrambleBoard(Button[] buttons)
{
    for (int x = 100 * buttons.Count(); x > 0; x--)
    {
        int first = rand.Next(buttons.Count());
        int second = rand.Next(buttons.Count());


        Button temp = buttons[first];
        buttons[first] = buttons[second];
        buttons[second] = temp;
    }

    return buttons;
}

答案 2 :(得分:0)

你的问题已得到解答,但我想我会分享一个很好的小技巧,用LINQ和Guid来改组一个集合。这会创建一个随机排序的列表,其中包含很好的值。

private Button[] scrambleBoard(Button[] buttons)
{
    return buttons.OrderBy(b => Guid.NewGuid()).ToArray();
}