如何创建非重复随机数的数组

我在C#中有一个彩票应用程序,它接受要绘制的数字的数量以及要绘制的最大数量。我已编码为创建一个包含所需随机数的数组,但我需要它们是唯一的并且我很难做到这一点如果有人能给我一些建议,我将非常感激,谢谢

这是我到目前为止的代码:

class Lottery { static int[] numberHolder; //array to be filled with numbers up to an //amount entered by the user eg 42 Max static int[] drawHolder; //array to hold the each random number //drawn from the pool of numbers eg 7 numbers public Lottery() //Lottery class Constructor { } //method which takes in a number limit and amount of numbers to be drawn public String drawNumbers(int numLimit, int numAmount) { Random RandomNumber = new Random(); for (int i = 0; i < numLimit ; i++) //loop to fill up numberHolder array // with predefined limit of numbers { numberHolder[i] = i++; } for (int i = 0; i < numAmount; i++) { // code to pick unique random numbers no greater than numAmount // and add them to the drawHolder[] array drawHolder[i] = RandomNumber.Next(1, numLimit); } //return the drawHolder array to String return null; } } 

在我看来,你应该改变你的方法。

而不是想“我将生成随机索引来选择我的数字”,你必须确保你没有得到任何重复,我只是将数组洗牌并首先取得你需要的X. 这样,您无需担心索引或重复项。

所以你的第二个for循环将改为

 drawHolder = numberHolder.OrderBy(x => new Guid()).Take(numAmount); 

(请注意我已经使用了new Guid()因此您可以删除RandomNumber声明行。如前所述,GUID是一个唯一值,并不意味着用作随机数。您也可以使用x => RandomNumber.Next() ,但如果你真的需要一个强大而可靠的舒适,请阅读Fisher-Yates )

您还可以使用简单的Enumerable.Range替换numberHolder数组

所以你的整个代码将成为(请注意我已经改变了你的方法名称以使用C#约定,方法名称应该在PascalCase中)

 public string DrawNumbers(int numLimit, int numAmount) { drawHolder = Enumerable.Range(0, numLimit).OrderBy(x => new Guid()).Take(numAmount); return string.Join(", ", drawHolder); } 

有几个选项,您可以使用Contains方法。

 numberHolder.Contains(value) 

Any()方法。

 numberHolder.Any(x=>x == value); 

听起来像洗牌一样比生成随机数更好。 你可以这样做:

 int[] ShuffleArray(int[] array) { Random r = new Random(); for (int i = array.Length; i > 0; i--) { int j = r.Next(i); int k = array[j]; array[j] = array[i - 1]; array[i - 1] = k; } return array; } 

归功于@RohitArora 。

在非重复整数数组上使用混洗算法很容易实现:

 public int[] GenerateNonRepeatingNumbers(int seed, int min, int range) { // Make sure range is an appropriate value if (range <= 0) { throw new ArgumentException("Range must be greater than zero."); } // Make an array to hold our numbers int[] numbers = new int[range]; // Seed the RNG. Random rng = new Random(seed); // Fill the array with all numbers from min to min + range for (int i = 0; i < range; numbers[i] = min + i++) { } int a = 0, // Swap index t = 0; // Temporary value storage // Scramble the values for (int i = 0; i < range; i++) { // Get a random index that isn't i while ((a = rng.Next(range)) == i) { }; // Store the old value at i t = numbers[i]; // Change the old value to the value at the random index numbers[i] = numbers[a]; // Set value at random index to our old value from numbers[i] numbers[a] = t; } return numbers; } 

我会保持简单:

 private Random _rnd = new Random(); public String drawNumbers(int numLimit, int numAmount) { return String.Join("," , Enumerable .Range(1, numLimit) .OrderBy(x => _rnd.Next()) .Take(numAmount)); } 

如果您快速连续调用该方法,请将Random实例的声明保留在方法之外,以防止返回相同的序列。

我会像这样使用Enumerable.Distinct :

 public String drawNumbers(int numLimit, int numAmount) { var numbers = Infinite(() => random.Next(numLimit)).Distinct().Take(numAmount); return string.Join(" ", numbers); } private Random random = new Random(); private static IEnumerable Infinite(Func generator) { while (true) yield return generator(); } 

在大多数numLimit较大且numAmount为10或更小的彩票中,此方法比创建和numLimit排列长度为numLimit的数组更有效。

如果涉及真钱,你应该使用比RandomGuid更好的随机生成器。 这是一个完整的Lottery类,它使用加密随机数生成器 (基于Microsoft的RNGCryptoServiceProvider )。

 class Lottery { // Use Random if this is in a school project or toy application // private Random randomGenerator = new Random(); // Use CryptoRandom if you're dealing with real money or prizes private CryptoRandom randomGenerator = new CryptoRandom(); //method which takes in a number limit and amount of numbers to be drawn public String drawNumbers(int numLimit, int numAmount) { return drawNumbers(1, numLimit, numAmount); } // takes the minimum and maximum lottery numbers and how many numbers to draw public String drawNumbers(int minNumber, int maxNumber, int count) { if (maxNumber < minNumber) return string.Empty; int maxCount = (int)Math.Min(int.MaxValue, 1L + maxNumber - minNumber); if (count > maxCount) count = maxCount; if (count < 1) return string.Empty; var numbers = Infinite(() => randomGenerator.Next(minNumber, maxNumber)).Distinct().Take(count); return string.Join(" ", numbers); } private static IEnumerable Infinite(Func generator) { while (true) yield return generator(); } private class CryptoRandom { private readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider(); private readonly byte[] _uint32Buffer = new byte[4]; public int Next(int minValue, int maxValue) { if (minValue == maxValue) return minValue; long diff = (long)maxValue - minValue; const long Max = 1L + uint.MaxValue; long randLimit = Max - (Max % diff); uint rand; do { _rng.GetBytes(_uint32Buffer); rand = BitConverter.ToUInt32(_uint32Buffer, 0); } while (rand >= randLimit); return (int)(minValue + (rand % diff)); } } } 

有很多方法可以做到这一点。 您可以排序然后比较if array[i] == array[i+1]