非重复随机数

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

如何在C#中做到这一点

注意我需要像这样循环

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

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

究竟是什么意思“不应该重复”? 如果你的意思是你不想得到任何副本,那么你应该基本上取一个数字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的单个实例Random用它。 (请注意,它不是线程安全的,这很痛苦。)例如:

 private static readonly Random Rng = new Random(); public int NextNumber() { return Rng.Next(20) + 1; } 

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

 public int NextNumber(Random rng) { return rng.Next(20) + 1; } 

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

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

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

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

 ///  /// Returns all numbers, between min and max inclusive, once in a random sequence. ///  IEnumerable UniqueRandom(int minInclusive, int maxInclusive) { List candidates = new List(); 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); } } 

你可以像这样使用它:

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

一个IEnumerable实现,基于Hallgrim的答案:

 public class UniqueRandoms : IEnumerable { Random _rand = new Random(); List _candidates; public UniqueRandoms(int maxInclusive) : this(1, maxInclusive) { } public UniqueRandoms(int minInclusive, int maxInclusive) { _candidates = Enumerable.Range(minInclusive, maxInclusive - minInclusive + 1).ToList(); } public IEnumerator GetEnumerator() { while (_candidates.Count > 0) { int index = _rand.Next(_candidates.Count); yield return _candidates[index]; _candidates.RemoveAt(index); } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } 

我这样做了一段时间。 我不知道它与效率,随机性等方面的其他方法相比如何。但它似乎有效:

 List integers = new List() { 1, 2, 3, 4, 5, 6,7, 8, 9, 10, 11, 12 }; Random rnd = new Random(); var ints = from i in integers orderby rnd.Next(integers.Count) select i; 

来自MSDN

“改善随机性的一种方法是使种子值与时间有关。”

另一个事实

你应该“创建一个随机数来随时间生成许多随机数”。 这将增强随机生成

 class Program { static void Main(string[] args) { List list = new List(); int val; Random r; int IntialCount = 1; int count = 7 ; int maxRandomValue = 8; while (IntialCount <= count) { r = new Random(); val = r.Next(maxRandomValue); if (!list.Contains(val)) { list.Add(val); IntialCount++; } } } } 

以下方式是非常好的方法,我在这里使用一个字符串,你可以将列表的类型改为你想要的任何东西……,试试看:

  List NamesList = new List() { "Name1", "Name2", "Name3", "Name4", "Name5" }; Random rnd = new Random(); //Now to get random of the above "Without Repeating.." for (int i = 0; i <= NamesList.Count - 1; i++) { int TheSelectedRand = rnd.Next(NamesList.Count); string MyRandNumber = NamesList[TheSelectedRand]; //Print or use your item here NamesList.Remove(NamesList[TheSelectedRand]); } 

打击代码生成65到0到92之间的唯一随机数,并返回数组中的唯一随机数。

 public static int[] RandomNumbers_Supplier() { Random R = new Random(); int[] RandomNumbers = new int[65]; int k = 0, Temp; bool IsRepetitive = false; while (k < 65) { Temp = R.Next(0, 92); for (int i = 0; i < 65; i++) { IsRepetitive = false; if (RandomNumbers[i] == Temp) { IsRepetitive = true; break; } } if (!IsRepetitive) { RandomNumbers[k] = Temp; k++; } } return(RandomNumbers) } 
 static void Main(string[] args) { //Randomize 15 numbers out of 25 - from 1 to 25 - in ascending order var randomNumbers = new List(); var randomGenerator = new Random(); int initialCount = 1; for (int i = 1; i <= 15; i++) { while (initialCount <= 15) { int num = randomGenerator.Next(1, 26); if (!randomNumbers.Contains(num)) { randomNumbers.Add(num); initialCount++; } } } randomNumbers.Sort(); randomNumbers.ForEach(x => Console.WriteLine(x)); }