如何使用C#生成随机并唯一的数字?

咨询区

  • Christian Peut

我的项目中需要生成若干个并且唯一的随机数,我用的是 System.Random,种子给的是 DateTime.Now.Ticks ,参考如下代码:.

private void NewNumber()
{
    Random a = new Random(DateTime.Now.Ticks.GetHashCode());

    MyNumber = a.Next(0, 10);
}

当我多次调用 NewNumber() 方法时,我发现会经常出现重复的值,一些朋友说是因为每次都 new 了一下 Random 所致,建议提取出来,代码如下:

public Random a = new Random(DateTime.Now.Ticks.GetHashCode());
private void NewNumber()
{
    MyNumber = a.Next(0, 10);
}

虽然随机性达到了,但我发现还是会存在 重复 的情况,请问是否有更好的解决方法。

回答区

  • tsme86

如果你仅仅是需要在  0-9 之间做 随机唯一 的话,我建议你用 洗牌策略 来打乱数组元素即可,参考如下代码:

        static void Main(string[] args)
        {
            var nums = Enumerable.Range(0, 10).ToArray();
            var rnd = new Random();

            // Shuffle the array
            for (int i = 0; i < nums.Length; ++i)
            {
                int randomIndex = rnd.Next(nums.Length);
                int temp = nums[randomIndex];
                nums[randomIndex] = nums[i];
                nums[i] = temp;
            }

            // Now your array is randomized and you can simply print them in order
            for (int i = 0; i < nums.Length; ++i)
                Console.WriteLine(nums[i]);
        }

  • JOSEFtw

如果你的生成范围小,我建议你用 Guid.NewGuid() 来实现随机性,但范围大的话,我不建议使用,因为性能是真的很差,参考代码如下:

        static void Main(string[] args)
        {
            var result = Enumerable.Range(0, 9).OrderBy(g => Guid.NewGuid()).ToArray();

            for (int i = 0; i < result.Length; ++i)
                Console.WriteLine(result[i]);
        }

  • Vasily Novsky

我是借用 HashSet 来找到 N 个随机并唯一的数字,道理很简单,HashSet 本身就可以保证数字的唯一性,参考如下代码:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    class RnDHash
    {
        static void Main()
        {
            HashSet<int> rndIndexes = new HashSet<int>();
            Random rng = new Random();
            int maxNumber;
            Console.Write("Please input Max number: ");
            maxNumber = int.Parse(Console.ReadLine());
            int iter = 0;
            while (rndIndexes.Count != maxNumber)
            {
                int index = rng.Next(maxNumber);
                rndIndexes.Add(index);
                iter++;
            }
            Console.WriteLine("Random numbers were found in {0} iterations: ", iter);
            foreach (int num in rndIndexes)
            {
                Console.WriteLine(num);
            }
            Console.ReadKey();
        }
    }
}

点评区

从时间复杂度以及条件允许的情况下,我觉得 洗牌策略 是一个好方案,其次是 HashSet,最后是 Guid.NewGuid(),这题目相信能给大家提供好的思路。