Generating random, unique values C#

2018-12-31 23:14发布

问题:

I\'ve searched for a while and been struggling to find this, I\'m trying to generate several random, unique numbers is C#. I\'m using System.Random, and I\'m using a datetime.now.ticks seed:

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

I\'m calling NewNumber() regularly, but the problem is I often get repeated numbers. Some people suggested because I was declaring the random every time I did it, it would not produce a random number, so I put the declaration outside my function. Any suggestions or better ways than using System.Random ? Thank you

回答1:

I\'m calling NewNumber() regularly, but the problem is I often get repeated numbers.

Random.Next doesn\'t guarntee the number to be unique. Also your range is from 0 to 10 and chances are you will get duplicate values. May be you can setup a list of int and insert random numbers in the list after checking if it doesn\'t contain the duplicate. Something like:

public Random a = new Random(); // replace from new Random(DateTime.Now.Ticks.GetHashCode());
                                // Since similar code is done in default constructor internally
public List<int> randomList = new List<int>();
int MyNumber = 0;
private void NewNumber()
{
    MyNumber = a.Next(0, 10);
    if (!randomList.Contains(MyNumber))
        randomList.Add(MyNumber);
}


回答2:

You might try shuffling an array of possible ints if your range is only 0 through 9. This adds the benefit of avoiding any conflicts in the number generation.

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


回答3:

I\'m posting a correct implementation of a shuffle algorithm, since the other one posted here doesn\'t produce a uniform shuffle.

As the other answer states, for small numbers of values to be randomized, you can simply fill an array with those values, shuffle the array, and then use however many of the values that you want.

The following is an implementation of the Fisher-Yates Shuffle (aka the Knuth Shuffle). (Read the \"implementation errors\" section of that link (search for \"always selecting j from the entire range of valid array indices on every iteration\") to see some discussion about what is wrong with the other implementation posted here.)

using System;
using System.Collections.Generic;

namespace ConsoleApplication2
{
    static class Program
    {
        static void Main(string[] args)
        {
            Shuffler shuffler = new Shuffler();
            List<int> list = new List<int>{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            shuffler.Shuffle(list);

            foreach (int value in list)
            {
                Console.WriteLine(value);
            }
        }
    }

    /// <summary>Used to shuffle collections.</summary>

    public class Shuffler
    {
        /// <summary>Creates the shuffler with a <see cref=\"MersenneTwister\"/> as the random number generator.</summary>

        public Shuffler()
        {
            _rng = new Random();
        }

        /// <summary>Shuffles the specified array.</summary>
        /// <typeparam name=\"T\">The type of the array elements.</typeparam>
        /// <param name=\"array\">The array to shuffle.</param>

        public void Shuffle<T>(IList<T> array)
        {
            for (int n = array.Count; n > 1; )
            {
                int k = _rng.Next(n);
                --n;
                T temp = array[n];
                array[n] = array[k];
                array[k] = temp;
            }
        }

        private System.Random _rng;
    }
}


回答4:

NOTE, I dont recommend this :). Here\'s a \"oneliner\" as well:

//This code generates numbers between 1 - 100 and then takes 10 of them.
var result = Enumerable.Range(1,101).OrderBy(g => Guid.NewGuid()).Take(10).ToArray();


回答5:

Depending on what you are really after you can do something like this:

using System;
using System.Collections.Generic;
using System.Linq;

namespace SO14473321
{
    class Program
    {
        static void Main()
        {
            UniqueRandom u = new UniqueRandom(Enumerable.Range(1,10));
            for (int i = 0; i < 10; i++)
            {
                Console.Write(\"{0} \",u.Next());
            }
        }
    }

    class UniqueRandom
    {
        private readonly List<int> _currentList;
        private readonly Random _random = new Random();

        public UniqueRandom(IEnumerable<int> seed)
        {
            _currentList = new List<int>(seed);
        }

        public int Next()
        {
            if (_currentList.Count == 0)
            {
                throw new ApplicationException(\"No more numbers\");
            }

            int i = _random.Next(_currentList.Count);
            int result = _currentList[i];
            _currentList.RemoveAt(i);
            return result;
        }
    }
}


回答6:

And here my version of finding N random unique numbers using HashSet. Looks pretty simple, since HashSet can contain only different items. It\'s interesting - would it be faster then using List or Shuffler?

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


回答7:

Check this ready-to-use method: Give in a range & count of number you want to get.

public static int[] getUniqueRandomArray(int min, int max, int count) {
    int[] result = new int[count];
    List<int> numbersInOrder = new List<int>();
    for (var x = min; x < max; x++) {
        numbersInOrder.Add(x);
    }
    for (var x = 0; x < count; x++) {
        var randomIndex = Random.Range(0, numbersInOrder.Count);
        result[x] = numbersInOrder[randomIndex];
        numbersInOrder.RemoveAt(randomIndex);
    }

    return result;
}


回答8:

You could also use a dataTable storing each random value, then simply perform the random method while != values in the dataColumn



回答9:

randomNumber function return unqiue integer value between 0 to 100000

  bool check[] = new bool[100001];
  Random r = new Random();
  public int randomNumber() {
      int num = r.Next(0,100000);
       while(check[num] == true) {
             num = r.Next(0,100000);
     }
    check[num] = true;
   return num;
 }


回答10:

You can use basic Random Functions of C#

Random ran = new Random();
int randomno = ran.Next(0,100);

you can now use the value in the randomno in anything you want but keep in mind that this will generate a random number between 0 and 100 Only and you can extend that to any figure.



回答11:

Try this:

private void NewNumber()
  {
     Random a = new Random(Guid.newGuid().GetHashCode());
     MyNumber = a.Next(0, 10);
  }

Some Explnations:

Guid : base on here : Represents a globally unique identifier (GUID)

Guid.newGuid() produces a unique identifier like \"936DA01F-9ABD-4d9d-80C7-02AF85C822A8\"

and it will be unique in all over the universe base on here

Hash code here produce a unique integer from our unique identifier

so Guid.newGuid().GetHashCode() gives us a unique number and the random class will produce real random numbers throw this