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

时间:2014-03-29 22:23:02

标签: c# arrays for-loop random tostring

我在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;
    }





}

9 个答案:

答案 0 :(得分:6)

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

而不是思考&#34;我会生成随机索引来选择我的数字&#34;,你必须确保你没有得到任何副本,我只是将数组洗牌并采取首先你需要X.这样,您就不必担心索引或重复。

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

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

(请注意我已使用new Guid(),因此您可以删除RandomNumber声明行。如前所述,GUID是一个唯一值,并不意味着要使用作为一个随机的gen。你也可以使用x => RandomNumber.Next(),但是如果你真的需要一个强大而可靠的shuffe,请阅读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);
} 

答案 1 :(得分:0)

听起来像改组你的阵列比生成随机数更好。你可以这样做:

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

答案 2 :(得分:0)

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

numberHolder.Contains(value)

Any()方法。

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

答案 3 :(得分:0)

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

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;
    }

答案 4 :(得分:0)

我会保持简单:

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实例的声明保留在方法之外,以防止返回相同的序列。

答案 5 :(得分:0)

我这样使用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<T> Infinite<T>(Func<T> generator) {
    while (true) yield return generator();
}

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

如果涉及真钱,您应该使用比RandomGuid更好的随机性生成器。这是一个使用a cryptographic random number generator的完整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<T> Infinite<T>(Func<T> 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));
        }
    }
}

答案 6 :(得分:0)

为时已晚,但我使用了由我创建的名为M_Randomizer的方法。

using System;
class Randomizer
{
    public int[] M_Randomizer(int x)
    {
        bool b = false;
        if (x < -1)
        {
            b = true;
            x = -1 * x;
        }
        if(x == -1)
            x = 0;
        if (x < 2)
            return new int[x];

        int[] site;
        int k = new Random(Guid.NewGuid().GetHashCode()).Next() % 2;
        if (x == 2)
        {
            site = new int[2];
            site[0] = k;
            site[1] = 1 - site[0];
            return site;
        }
        else if (x == 3)
        {
            site = new int[3];
            site[0] = new Random(Guid.NewGuid().GetHashCode()).Next(0, 3);
            site[1] = (site[0] + k + 1) % 3;
            site[2] = 3 - (site[0] + site[1]);
            return site;
        }
        site = new int[x];
        int a = 0, m = 0, n = 0, tmp = 0;
        int[] p = M_Randomizer(3);
        int[] q;

        if (x % 3 == 0)
            q = M_Randomizer(x / 3);
        else
            q = M_Randomizer((x / 3) + 1);
        if (k == 0)
        {
            for (m = 0; m < q.Length; m++)
            {
                for (n = 0; n < p.Length && a < x; n++)
                {
                    tmp = (q[m] * 3) + p[n];
                    if (tmp < x)
                    {
                        site[a] = tmp;
                        a++;
                    }
                }
            }
        }
        else
        {
            while (n < p.Length)
            {
                while (a < x)
                {
                    tmp = (q[m] * 3) + p[n];
                    if (tmp < x)
                    {
                        site[a] = tmp;
                        a++;
                    }
                    m = m + k;
                    if (m >= q.Length)
                        break;
                }
                m = m % q.Length;
                n++;
            }
        }

        a = (new Random(Guid.NewGuid().GetHashCode()).Next() % 2) + 1;
        k = new Random(Guid.NewGuid().GetHashCode()).Next() % 10;
        if (k > 5)
            for (int i = a; i < k; i++)
                while (a < site.Length)
                {
                    if (k % (a + 1) == 0)
                    {
                        tmp = site[a - 1];
                        site[a - 1] = site[a];
                        site[a] = tmp;
                    }
                    a = a + 2;
                }

        k = new Random(Guid.NewGuid().GetHashCode()).Next() % 10;
        if (k > 5)
        {
            n = x / 2;
            k = 0;
            if (x % 2 != 0)
                k = (new Random(Guid.NewGuid().GetHashCode()).Next() % 2);

            p = new int[n + k];
            m = (x - n) - k;
            for (a = 0; m < x; a++, m++)
                p[a] = site[m];

            m = n + k;
            for (a = (x - m) - 1; a >= 0; a--, m++)
                site[m] = site[a];

            for (a = 0; a < p.Length; a++)
                site[a] = p[a];
        }

        int[] site2;
        int[] site3 = new int[x];
        if (b)
            return site;
        else
            site2 = M_Randomizer(-1 * x);

        for (a = 0; a < site.Length; a++)
            site3[site2[a]] = site[a];

        return site3;
    }

    public int[] M_Randomizer(int x, int start)
    {
        int[] dm = M_Randomizer(x);

        for(int a = 0; a < x; a++)
            dm[a] = dm[a] + start;

        return dm;
    }
}

答案 7 :(得分:0)

不确定这是最快的方法,但我想出了以下解决方案:

List<NotificationModel> notifications

答案 8 :(得分:-2)

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