Генерация случайных, уникальных значений C#
Я искал некоторое время и изо всех сил пытался найти это, я пытаюсь сгенерировать несколько случайных, уникальных чисел C#. Я использую 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? Спасибо
19 ответов
Я регулярно звоню в 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);
}
Вы можете попробовать перетасовать массив возможных целых чисел, если ваш диапазон составляет только от 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]);
ПРИМЕЧАНИЕ, я не рекомендую это:). Вот еще и "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();
Я публикую правильную реализацию алгоритма тасования, так как другой, размещенный здесь, не производит равномерного тасования.
Как говорится в другом ответе, для рандомизации небольшого числа значений вы можете просто заполнить массив этими значениями, перемешать массив, а затем использовать сколько угодно значений.
Ниже приведена реализация 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;
}
}
Проверьте этот готовый к использованию метод: введите диапазон и количество, которое вы хотите получить.
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;
}
То же, что и ответ @Habib, но как функция:
List<int> randomList = new List<int>();
int UniqueRandomInt(int min, int max)
{
var rand = new Random();
int myNumber;
do
{
myNumber = rand.Next(min, max);
} while (randomList.Contains(myNumber));
return myNumber;
}
Если randomList является свойством класса, UniqueRandomInt вернет уникальные целые числа в контексте того же экземпляра этого класса. Если вы хотите, чтобы он был уникальным в глобальном масштабе, вам нужно сделать randomList статическим.
В зависимости от того, что вы действительно после того, как вы можете сделать что-то вроде этого:
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;
}
}
}
И вот моя версия поиска 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();
}
}
}
Я заметил, что принятый ответ продолжает добавлять int в список и проверяет их с помощью if (!randomList.Contains(MyNumber))
и я думаю, что это плохо масштабируется, особенно если вы продолжаете просить новые цифры.
Я бы сделал наоборот.
- Создавать список при запуске, линейно
- Получить случайный индекс из списка
- Удалите найденный 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;
}
}
}
Random r = new Random(); int[] v = new int[10];
for (int i = 0; i < 10; i++)
{
v[i] = r.Next(1, 25); // random numbers between (1) and (25)
for (int j = 0; j < i; j++)
{
if (v[j] == v[i]) // if it is a duplicated value, create new one!
i--;
}
}
for (int i = 0; i < 10; i++)
textBox1.Text += v[i].ToString() + " ";
- с функциональным способом*
static Func<int> GetNextUniqueIntegerFunc(int min, int max)
{
var list = new List<int>();
var random = new Random();
int getNextValue()
{
while (true)
{
var random_number = random.Next(min, max);
if (!list.Contains(random_number))
{
list.Add(random_number);
return random_number;
}
}
}
return getNextValue;
}
Возможно, это немного поздно, но вот более подходящий код, например, когда вам нужно использовать циклы:
List<int> genered = new List<int>();
Random rnd = new Random();
for(int x = 0; x < files.Length; x++)
{
int value = rnd.Next(0, files.Length - 1);
while (genered.Contains(value))
{
value = rnd.Next(0, files.Length - 1);
}
genered.Add(value);
returnFiles[x] = files[value];
}
Это консольное приложение позволит вам перетасовать алфавит пять раз в разном порядке.
using System;
using System.Linq;
namespace Shuffle
{
class Program
{
static Random rnd = new Random();
static void Main(string[] args)
{
var alphabet = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
Console.WriteLine("Alphabet : {0}", string.Join(",", alphabet));
for (int i = 0; i < 5; i++)
{
var shuffledAlphabet = GetShuffledAlphabet(alphabet);
Console.WriteLine("SHUFFLE {0}: {1}", i, string.Join(",", shuffledAlphabet));
}
}
static string[] GetShuffledAlphabet(string[] arr)
{
int?[] uniqueNumbers = new int?[arr.Length];
string[] shuffledAlphabet = new string[arr.Length];
for (int i = 0; i < arr.Length; i++)
{
int uniqueNumber = GenerateUniqueNumber(uniqueNumberArrays);
uniqueNumberArrays[i] = uniqueNumber;
newArray[i] = arr[uniqueNumber];
}
return shuffledAlphabet;
}
static int GenerateUniqueNumber(int?[] uniqueNumbers)
{
int number = rnd.Next(uniqueNumbers.Length);
if (!uniqueNumbers.Any(r => r == number))
{
return number;
}
return GenerateUniqueNumber(uniqueNumbers);
}
}
}
Вы также можете использовать dataTable для хранения каждого случайного значения, а затем просто выполнить случайный метод, в то время как!= Values в dataColumn
Уникальное случайное число от 0 до 9
int sum = 0;
int[] hue = new int[10];
for (int i = 0; i < 10; i++)
{
int m;
do
{
m = rand.Next(0, 10);
} while (hue.Contains(m) && sum != 45);
if (!hue.Contains(m))
{
hue[i] = m;
sum = sum + m;
}
}
Привет , здесь я разместил одно видео, и оно объясняет, как генерировать уникальное случайное число
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 чисел), как случайные.. спасибо........
Функция 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; }
Вы можете использовать основные случайные функции C#
Random ran = new Random();
int randomno = ran.Next(0,100);
Теперь вы можете использовать значение в randomno во всем, что вы хотите, но имейте в виду, что это будет генерировать случайное число между 0
а также 100
Только и вы можете распространить это на любую фигуру.
Попробуй это:
private void NewNumber()
{
Random a = new Random(Guid.newGuid().GetHashCode());
MyNumber = a.Next(0, 10);
}
Некоторые объяснения:
Guid
: base on here: представляет глобально уникальный идентификатор (GUID)
Guid.newGuid()
производит уникальный идентификатор, такой как "936DA01F-9ABD-4d9d-80C7-02AF85C822A8"
и это будет уникальным во всей базе вселенной здесь
Хеш-код здесь производит уникальное целое число из нашего уникального идентификатора
так Guid.newGuid().GetHashCode()
дает нам уникальное число, и случайный класс будет производить реальные случайные числа бросить это