非重复随机数

web*_*nia 8 c# random

要生成1-20的随机数,我需要选择性选择,它不应该是重复的.

如何在C#中执行此操作

注意我需要像这样循环

Random rnd = new Random()
rnd.Next(1,20)
for(int i =0; i<=20;i++)
{

}
Run Code Online (Sandbox Code Playgroud)

对于所有循环,数字应为1到20

Jon*_*eet 22

究竟是什么意思"不应该重复"?如果你的意思是你不想得到任何重复,那么你应该基本上取一个数字1-20的列表,将它们混洗,然后从列表的头部一次抓一个.有关重新排列列表的有效方法,请参阅此Stack Overflow答案.

如果你只是意味着你当前的尝试给出5,5,5,5,5,5,1,1,1,1,1,1,1,1,2,2,2,2,2等等,那么机会是你Random每次选择一个数字时都要创建一个新实例:不要这样做.每次创建实例时,它都会使用当前时间作为随机数生成器的"种子"(除非您明确指定一个).这意味着如果您快速连续创建多个实例,每个实例将获得相同的种子,因此给出相同的数字序列.

相反,使用单个实例Random并重用它.(请注意,它不是线程安全的,这很痛苦.)例如:

private static readonly Random Rng = new Random();

public int NextNumber()
{
    return Rng.Next(20) + 1;
}
Run Code Online (Sandbox Code Playgroud)

这不是线程安全的,但如果这是一个问题,请告诉我们.一种替代方案有时会传递给Random方法(当然,这通常会更复杂):

public int NextNumber(Random rng)
{
    return rng.Next(20) + 1;
}
Run Code Online (Sandbox Code Playgroud)

然后调用者可以适当地重用该实例.

如果您想要一种生成随机数的线程安全方法,您可能希望StaticRandomMiscUtil中查看我的类.

(请注意,使用rng.Next(1, 21)也可以正常工作 - 我碰巧更喜欢上面的版本,因为我认为它减少了对包容性/独占边界的猜测,但这是个人品味的问题.)


Hal*_*rim 18

此方法将生成所有数字,并且不会重复任何数字:

/// <summary>
/// Returns all numbers, between min and max inclusive, once in a random sequence.
/// </summary>
IEnumerable<int> UniqueRandom(int minInclusive, int maxInclusive)
{
    List<int> candidates = new List<int>();
    for (int i = minInclusive; i <= maxInclusive; i++)
    {
        candidates.Add(i);
    }
    Random rnd = new Random();
    while (candidates.Count > 0)
    {
        int index = rnd.Next(candidates.Count);
        yield return candidates[index];
        candidates.RemoveAt(index);
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它:

Console.WriteLine("All numbers between 0 and 20 in random order:");
foreach (int i in UniqueRandom(0, 20)) {
    Console.WriteLine(i);
}
Run Code Online (Sandbox Code Playgroud)