How to create an array of non repeating random numbers

让人想犯罪 __ 提交于 2019-11-29 14:18:06

In my opinion, you should change your approach.

Instead of thinking "I'll generate random indexes to pick my numbers", where you have to be sure you don't get any duplicates, I would simply shuffle the array and take the X first you need. That way, you don't need to worry about indexes or duplicates.

So your second for loop would be changed to

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

(Please note I've used new Guid() so you can remove your RandomNumber declaration line. As discussed before, a GUID is a unique value and not meant for to be used as a random gen. You could also use x => RandomNumber.Next(), but if you really need a strong and reliable shuffe, read about Fisher-Yates)

You can also replace your numberHolder array with a simple Enumerable.Range

So your whole code would become (And please note I've changed your method name to use C# conventions, method names should be in PascalCase)

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

    return string.Join(", ", drawHolder);
} 

There are a few options, you could use the Contains method.

numberHolder.Contains(value)

The Any() method.

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

Sounds like shuffling your array is better than generating random numbers. You could do it like this:

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

Credit goes to @RohitArora.

This is easily achieved using a shuffling algorithm on an array of non-repeating integers:

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

I would keep it simple:

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

Keep the declaration of the Random instance outside of the method to prevent returning identical sequences if you call the method in quick succession.

I'd use Enumerable.Distinct like this:

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

In most lotteries where numLimit is large and numAmount is 10 or less, this method is more efficient than creating and shuffling an array of length numLimit.

If real money is involved, you should use a better randomness generator than Random or Guid. Here's a full Lottery class that uses a cryptographic random number generator (based on Microsoft's 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));
        }
    }
}

It's too late but I use a Method named M_Randomizer created by me.

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

Lots of ways to do this. You could sort and then compare if array[i] == array[i+1].

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!