it-roy-ru.com

Генерация случайных, уникальных значений 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? Спасибо

23
Christian Peut

Я регулярно вызываю 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);
}
21
Habib

Вы можете попробовать перетасовать массив возможных целых чисел, если ваш диапазон составляет только от 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]);
15
itsme86

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

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

Ниже приведена реализация 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;
    }
}
9
Matthew Watson

ПРИМЕЧАНИЕ, я не рекомендую это :). Вот и «один вкладыш»:

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

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

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;
        }
    }
}
1
Andrew Savinykh

И здесь моя версия поиска 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();
        }
    }
}
0
Vasily Novsky

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

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;
}
0
Evren Ozturk