Создание случайных, уникальных значений С#

Я искал некоторое время и пытался найти это, я пытаюсь сгенерировать несколько случайных, уникальных чисел С#. Я использую System.Random, и я использую семя DateTime.Now.Ticks:

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

Я регулярно звоню в NewNumber(), но проблема в том, что я часто получаю повторные номера. Некоторые люди предложили, потому что я объявлял случайное число каждый раз, когда я делал это, оно не получало бы случайное число, поэтому я поместил объявление вне своей функции. Любые предложения или лучшие способы, чем использование System.Random? Спасибо

Ответ 1

Я регулярно звоню в NewNumber(), но проблема в том, что я часто получаю повторные номера.

Random.Next не гарантирует уникальность числа. Также ваш диапазон от 0 до 10, и, скорее всего, вы получите повторяющиеся значения. Возможно, вы можете настроить список int и вставить случайные числа в список после проверки, не содержит ли он дубликата. Что-то вроде:

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

Вы можете попробовать перетасовать массив возможных int, если ваш диапазон составляет всего от 0 до 9. Это добавляет преимущество избежания конфликтов в генерации чисел.

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

ПРИМЕЧАНИЕ. Я не рекомендую это:). Здесь также "oneliner":

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

Ответ 4

Я отправляю правильную реализацию алгоритма перетасовки, так как другая, размещенная здесь, не создает равномерного тасования.

Как утверждается в другом ответе, для небольшого числа значений, которые должны быть рандомизированы, вы можете просто заполнить массив этими значениями, перетасовать массив и затем использовать любое количество значений, которые вы хотите.

Ниже приведена реализация Fisher-Yates Shuffle (также известный как Knuth Shuffle). (Прочитайте раздел "Ошибки реализации" этой ссылки (найдите "всегда выбирайте j из всего диапазона допустимых индексов массива на каждой итерации" ), чтобы посмотреть, как это происходит с другой версией, размещенной здесь.)

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

Ответ 5

Проверьте этот готовый к использованию метод: укажите диапазон и количество чисел, которое вы хотите получить.

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

Ответ 6

В зависимости от того, что вы действительно после того, как вы можете сделать что-то вроде этого:

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

Ответ 7

И вот моя версия поиска N случайных уникальных чисел с использованием HashSet. Выглядит довольно просто, поскольку HashSet может содержать только разные элементы. Это интересно - было бы быстрее, чем использовать List или 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();
        }
    }
}

Ответ 8

Я отметил, что принятый ответ продолжает добавлять int в список и продолжает проверять их с помощью if (!randomList.Contains(MyNumber)) и я думаю, что это плохо масштабируется, особенно если вы продолжаете запрашивать новые номера.

Я бы сделал наоборот.

  1. Генерация списка при запуске, линейно
  2. Получить случайный индекс из списка
  3. Удалить найденный int из списка

Это потребует немного больше времени при запуске, но будет гораздо лучше масштабироваться.

public class RandomIntGenerator
{
    public Random a = new Random();
    private List<int> _validNumbers;

    private RandomIntGenerator(int desiredAmount, int start = 0)
    {
        _validNumbers = new List<int>();
        for (int i = 0; i < desiredAmount; i++)
            _validNumbers.Add(i + start);
    }

    private int GetRandomInt()
    {
        if (_validNumbers.Count == 0)
        {
            //you could throw an exception here
            return -1;
        }
        else
        {
            var nextIndex = a.Next(0, _validNumbers.Count - 1);
            var number    = _validNumbers[nextIndex];
            _validNumbers.RemoveAt(nextIndex);
            return number;
        }
    }
}

Ответ 9

Вы также можете использовать dataTable, сохраняя каждое случайное значение, а затем просто выполняйте случайный метод while!= values ​​в dataColumn

Ответ 10

Функция randomNumber возвращает необработанное целочисленное значение в диапазоне от 0 до 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;
 }

Ответ 11

привет, здесь я разместил одно видео, и оно объясняет, как генерировать уникальное случайное число

  public List<int> random_generator(){

  Random random = new Random();

   List<int> random_container = new List<int>;

     do{

       int random_number = random.next(10);

      if(!random_container.contains(random_number){

       random_container.add(random_number)
  }
}
   while(random_container.count!=10);


     return random_container; 
  }

здесь ,, в случайном контейнере вы получите не повторяющиеся 10 чисел, начиная с 0 до 9 (10 чисел), как случайные.. спасибо........

Ответ 12

Вы можете использовать базовые случайные функции С#

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

теперь вы можете использовать значение в случайном порядке во всем, что хотите, но имейте в виду, что это приведет к случайному числу между 0 и 100 Only, и вы можете расширить его до любой цифры.

Ответ 13

Попробуйте следующее:

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

Некоторые объяснения:

Guid: база здесь: представляет глобально уникальный идентификатор (GUID)

Guid.newGuid() создает уникальный идентификатор типа "936DA01F-9ABD-4d9d-80C7-02AF85C822A8"

и он будет уникальным во всем мире здесь

Хэш-код здесь выдает уникальное целое из нашего уникального идентификатора

поэтому Guid.newGuid().GetHashCode() дает нам уникальное число, и случайный класс будет генерировать реальные случайные числа, бросая это