День сто пятнадцатый. #ЗаметкиНаПолях
Случайные числа в C#
Вокруг генерации случайных чисел всегда ходит много мифов и поэтому возникает много путаницы. Можно ли использовать простую конструкцию:
На самом деле в подавляющем большинстве случаев для генерации случайных (псевдослучайных) чисел достаточно следующего кода:
1. Указание числа посева (seed) в конструкторе класса
Для случайного перемешивания небольших коллекций вполне подойдёт простой код LINQ:
Источники:
- https://www.youtube.com/watch?v=kW84q8WOBdU
- https://stackoverflow.com/questions/273313/randomize-a-listt/
Случайные числа в C#
Вокруг генерации случайных чисел всегда ходит много мифов и поэтому возникает много путаницы. Можно ли использовать простую конструкцию:
var random = new Random();или же необходимо подключать криптографические библиотеки?
На самом деле в подавляющем большинстве случаев для генерации случайных (псевдослучайных) чисел достаточно следующего кода:
Random random = new Random();Однако есть несколько ограничений:
Console.WriteLine(random.Next());
1. Указание числа посева (seed) в конструкторе класса
Random
приведёт к созданию одинаковых последовательностей случайных чисел, поэтому используйте конструктор без параметров. Например, следующий код будет генерировать одну и ту же последовательность при каждом запуске:Random random = new Random(10010);2. Создавайте объект
for (int i = 0; i < 10; i++)
{
Console.WriteLine(random.Next());
}
Random
только один раз. Если метод должен использовать случайное число, не создавайте новый объект Random
внутри метода. Создайте его вне метода и передавайте в метод в качестве параметра:Random random = new Random();вместо
SomeMethod(random);
SomeMethod(new Random());Это связано с пунктом 1. Конструктор класса Random без параметров берёт в качестве числа посева системное время в формате тактов процессора (1 такт = 100 наносекунд). Однако по природе своей реализации системные часы не различают разницу во времени примерно в 15 миллисекунд. Поэтому последовательные вызовы конструктора класса
Random
могут привести к созданию нескольких одинаковых случайных последовательностей.Для случайного перемешивания небольших коллекций вполне подойдёт простой код LINQ:
var shuffeledList = somelist.OrderBy(x => random.Next());Для больших коллекций есть более эффективные алгоритмы, например, Фишера-Йетса (здесь используем метод-расширение для
IList
):private static Random rng = new Random();Использование:
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1) {
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
List<Product> products = GetProducts();Для небольшого количества случаев, когда требуется криптографически безопасное случайное число (например, при создании случайного пароля), используйте класс
products.Shuffle();
RNGCryptoServiceProvider
или наследуйте от System.Security.Cryptography.RandomNumberGenerator
.Источники:
- https://www.youtube.com/watch?v=kW84q8WOBdU
- https://stackoverflow.com/questions/273313/randomize-a-listt/