Генерировать различные случайные числа в C #
Просто интересно, можете ли вы подтвердить, что приведен следующий код, и сообщить, есть ли у него лучшие альтернативы?
Я пытаюсь создать набор различных случайных чисел от 1 до 100000.
Random rand = new Random(); List result = new List(); for (Int32 i = 0; i value == curValue)) { curValue = rand.Next(1, 100000); } result.Add(curValue); }
- Когда можно использовать обработку исключений для бизнес-логики?
- Проверка указателя NULL в C / C ++
- Завершение кода PHP NetBeans
- Может ли class Java добавлять метод вовремя?
- Покрытие кода, не показывающее результаты с помощью Xcode + gcov
- Как определить неиспользуемые определения css
- Когда использовать утверждение и когда использовать исключение
- Можете ли вы создавать представления sql / хранимую процедуру с использованием Entity Framework 4.1 Первый подход к коду
- Что означает == $ 0 (double equals dollar zero) в инструментах разработчика Chrome?
- Codesign API Dropbox не работает в Xcode 4.6.3: «Объект кода вообще не подписан»
- «Взаимодействие с пользователем не разрешено», пытаясь подписать приложение OSX с использованием кода
- Отключение автоматического форматирования в Visual Studio
- Не удается получить доступ к родительским элементам при работе с аннотациями макросов
Да, насколько я могу судить, код делает именно то, что вы хотите.
Прокрутка по списку для проверки каждого значения не очень эффективна. Вы можете поместить значения в HashSet
чтобы ускорить работу ckeck.
Поскольку «HashSet» не сохраняет порядок элементов, вам все равно нужен List
:
Random rand = new Random(); List result = new List (); HashSet check = new HashSet (); for (Int32 i = 0; i < 300; i++) { int curValue = rand.Next(1, 100000); while (check.Contains(curValue)) { curValue = rand.Next(1, 100000); } result.Add(curValue); check.Add(curValue); }
Не то, чтобы это имело бы большое значение, если вам просто нужно было 300 номеров, но было бы более эффективно использовать HashSet, который выполняет o (1) поиск, а не o (n), как и в List
Random rand = new Random(); HashSet result = new HashSet (); while (result.Count < 300) { result.Add(rand.Next(1, 1000000)); }
Повторно используйте человека. Как только вы захотите сделать, это набор чисел (Enumerable.Range будет делать), во-вторых, это случайное перемещение этих чисел. Вы можете найти ответ на эту проблему на SO, и благодаря решению LINQ это красиво, но, возможно, не самый быстрый, во всяком случае, я использую его, потому что мне нравится его красота.
Linq shuffling: http://www.code56.com/2009/02/lets-do-some-shuffling.html (мертвая ссылка). Очень похожая реализация: http://csharpsimple.blogspot.com/2012/01/shuffle-in-linq-part-2.html
Вкратце:
var rand = new Random(); return source.Select(t => new { Index = rand.Next(), Value = t }) .OrderBy(p => p.Index) .Select(p => p.Value);
Это будет делать то, что вы хотите, за исключением того, что выбрасывание числа, потому что вы его видели, уменьшает энтропию (случайность) последовательности.
Ваша версия будет работать, поэтому то, что я предлагаю, просто забавная альтернатива:
List result = new List (); Queue working = new Queue (new int[2] {1, 100000}); Random rand = new Random(); while (result.Count < 300) { int lower = working.Dequeue(); int upper = working.Dequeue(); int pivot = rand.Next(lower,upper); result.Add(pivot); if(lower < pivot) { working.Enqueue(lower); working.Enqueue(pivot); } if(pivot+1 < upper) { working.Enqueue(pivot + 1); working.Enqueue(upper); } }
В таких случаях я всегда думаю, что вам действительно не нужны случайные числа. Вместо этого вы больше собираетесь перетасовывать некоторые существующие числа.
Итак, как насчет того, чтобы выбрать диапазон, который вам нравится, например, var range = Enumerable.Range(1, 100000)
, перетасовать их и взять количество необходимых вам элементов, например, range.ToArray().Shuffle().Take(300)
?
Здесь можно найти одну реализацию алгоритма перетасовки. Я знаю, что это не метод расширения, который можно использовать описанным выше способом, но изменение подписи довольно просто.
Если вы хотите сделать предварительный сбой для предварительного создания списка из 100 000 ints, этот метод выполняется очень быстро:
static IList GetRandoms(int[] sample) { var rand = new Random(); var result = new int[300]; var count = sample.Length; for (int i = 0; i < 300; i++) { var index = rand.Next(count); result[i] = sample[index]; sample[index] = sample[--count]; } return result; }
Поэтому вы бы назвали это так:
var sample = Enumerable.Range(1, 100000).ToArray(); var data = GetRandoms(sample);
Изменил мой неряшливый ответ!
var result = new HashSet(); var random = new Random(); var seq = Enumerable.Range(1, 30).GetEnumerator(); while(seq.MoveNext()) { while(!result.Add(random.Next(1, 100000))); }
Я понимаю, что это действительно старая статья, но чтобы добавить в мой недавний опыт работу над одним и тем же строком (мне пришлось генерировать 100k случайных документов Id с иностранными идентификаторами, в которых оба должны были быть уникальными списками #).
Чтобы ускорить его, вы можете многопоточно его использовать с помощью parallel.for – если это так, вы не можете использовать hashset. Вместо этого используйте a, где byte будет просто ConcurrentDictionary из
взял время работы от ~ 1,5 часов до 20 минут для меня. Если вам нужно, я бы предложил использовать связанныйList для хранения, а не вместо очереди или списка, если у вас нет конкретной необходимости в произвольном доступе.