Генерация случайных, уникальных значений 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)) и я думаю, что это плохо масштабируется, особенно если вы продолжаете просить новые цифры.

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

  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;
        }
    }
}
      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() дает нам уникальное число, и случайный класс будет производить реальные случайные числа бросить это

Другие вопросы по тегам