nitin_ambupe Ответов: 3

Почему C# random возвращает одно и то же значение?


Я использовал метод Random class "Next(int32, int32) для генерации случайного числа, которое попадает в диапазон.
Допустим, диапазон довольно большой. Разница между парам1 и парам2 равна 100.

Если мне нужно случайное число в итерации (предположим, 5 раз), то 3 из 5 раз я получаю одно и то же значение.

Как получить случайное число, которое не повторяется для диапазона?
Или мне следует просто использовать генераторы случайных чисел, предоставляемые крипто-сервисом?

Что я уже пробовал:

1. Первое решение включало создание нового экземпляра в цикле.
public List<string> GetRandomRecords(List<string> records, int requiredRecords)
        {
            var numberOfRecords = records.Count;

            var randomRecords = new List<string>();

            for (int i = 0; i < requiredRecords; i++)
            {
                var randomGenerator = new Random();

                while (true)
                {
                    var randomIndex = randomGenerator.Next(0, numberOfRecords);

                    var record = records[randomIndex];

                    if (!randomRecords.Contains(record))
                    {
                        randomRecords.Add(record);
                        break;
                    }
                }
            }

            return randomRecords.OrderBy(item => Guid.NewGuid()).ToList();
        }


2. Изменено решение использовать тот же экземпляр в петлю.

public List<string> GetRandomRecords(List<string> records, int requiredRecords)
       {
           var numberOfRecords = records.Count;

           var randomRecords = new List<string>();

           var randomGenerator = new Random();

           for (int i = 0; i < requiredRecords; i++)
           {
               while (true)
               {
                   var randomIndex = randomGenerator.Next(0, numberOfRecords);

                   var record = records[randomIndex];

                   if (!randomRecords.Contains(record))
                   {
                       randomRecords.Add(record);
                       break;
                   }
               }
           }

           return randomRecords.OrderBy(item => Guid.NewGuid()).ToList();
       }

Patrice T

Покажи свой код !

Dave Kreskowiak

Это звучит так, как будто вы создаете новый экземпляр Random внутри цикла. Не делай этого! Но мы не можем этого сказать, потому что не видим вашего кода.

George Swan

Один из подходов для генерации уникальных случайных чисел в заданном диапазоне состоит в том, чтобы поместить все числа в требуемом диапазоне в массив. Перетасуйте массив и последовательно извлеките из него необходимые элементы.

3 Ответов

Рейтинг:
2

OriginalGriff

Природа "случайных чисел" состоит в том, что они никоим образом не гарантируют уникальность в таком небольшом наборе, как ваш: На самом деле они никогда не могут гарантировать уникальность независимо от размера выборки - следующее число не имеет никакого отношения к предыдущим, кроме статистического.
И создание экземпляра генератора случайных чисел внутри цикла не помогает, потому что он задан из системных часов, поэтому очень вероятно, что несколько экземпляров будут начинаться с одного и того же значения (учитывая, что Random не является истинно случайным, он псевдослучайный, как и все программные генераторы случайных чисел).

Если вы хотите рисовать только из пула уникальных чисел, то создайте новый список<int> и заполните его диапазоном значений. Затем используйте это, чтобы предоставить свою уникальную строку:

private Random randomGenerator = new Random();
public List<string> GetRandomRecords(List<string> records, int requiredRecords)
    {
    int numberOfRecords = records.Count;
    List<string> randomRecords = new List<string>();
    List<int> indexes = Enumerable.Range(0, requiredRecords).ToList();
    for (int i = 0; i < requiredRecords; i++)
        {
        int randomIndex = randomGenerator.Next(0, indexes.Count);
        int index = indexes[randomIndex];
        indexes.RemoveAt(randomIndex);
        string record = records[index];
        randomRecords.Add(record);
        }
    return randomRecords;
    }
}


Рейтинг:
2

ChienVH

Попробуйте этот код. Вы должны проверить каждое число, которое вы генерируете, против предыдущих чисел.

public List<string> GetRandomRecords(List<string> records, int requiredRecords)
{
	var numberOfRecords = records.Count;
	var randomRecords = new List<string>();
	var randomGenerator = new Random();
	int randomIndex;
	for (int i = 0; i < requiredRecords; i++)
	{
		do
		{
			randomIndex = randomGenerator.Next(0, numberOfRecords);
		} while(randomRecords.Contains(record));
		randomRecords.Add(randomIndex);
	}
	return randomRecords.OrderBy(item => Guid.NewGuid()).ToList();
}


nitin_ambupe

Это я уже делаю. Запись считается новой только в том случае, если она отсутствует в списке.
Проблема в том, что Random генерирует одно и то же число снова и снова, и иногда это застревает на довольно долгое время. (Похоже, что часть пользовательского интерфейса зависает).

Рейтинг:
0

CPallini

Предположим, вам нужно извлечь 5 цифры в списке 1..100 диапазон. Шансы получить один или несколько дубликатов равны:

p=(100^5 - 100*99*98*97*96)/100^5 ≅ 9.7 %

Таким образом, примерно в десяти процентах случаев вы получите dulpicates (если вы наблюдаете большую частоту, то либо есть ошибка в вашем коде, либо (менее вероятно) генератор случайных чисел неверен.

Чтобы избежать дубликатов без затрат времени проверка и отклонение подходите, следуйте алгоритму, который я описал здесь: Случайное извлечение 5 карт из колоды[^] (Я знаю, что это так. C++, но вы можете легко преобразовать его в C#).