Создайте 10000 неповторяющихся случайных чисел в PHP

Мне нужно разработать способ создания 10000 неповторяющихся случайных чисел в PHP, а затем поместить их в таблицу базы данных. Номер будет состоять из 12 цифр.

Как лучше всего это сделать?


person Ivan Tanasijevic    schedule 09.02.2011    source источник
comment
или, возможно, используйте php.net/manual/en/function.uniqid.php   -  person Alfred    schedule 09.02.2011


Ответы (4)


Это предполагает, что вы можете без проблем сгенерировать 12-значное случайное число (используйте getrandmax (), чтобы узнать, насколько большим вы можете получить ... согласно php.net, в некоторых системах 32k - это максимальное число, которое вы можете получить.

$array = array();

while(sizeof($array)<=10000){
  $number = mt_rand(0,999999999999);
  if(!array_key_exists($number,$array)){
     $array[$number] = null;
  }
}

foreach($array as $key=>$val){
  //write array records to db.
}

Вы можете использовать rand () или mt_rand (). Однако предполагается, что mt_rand () будет быстрее.

person dmcnelis    schedule 09.02.2011
comment
Нет необходимости выполнять in_array(), который замедлил бы это по мере увеличения числа генерируемых чисел. Просто используйте число в качестве ключа массива, что уменьшает количество повторяющихся проверок до if isset($array[$number]) { ... }. - person Marc B; 09.02.2011
comment
in_array Я считаю, что это требует линейного времени, поэтому весь алгоритм занимает квадратичное время. Сказав $array[$number] = null; и используя вместо этого array_key_exists, вы получите значительно лучшую производительность (близкую к линейной). - person erisco; 09.02.2011
comment
Я обновил приведенный выше код, чтобы отразить использование предложения @Marc B и предложения @erisco. - person dmcnelis; 09.02.2011
comment
Я думаю, как лучше всего это сделать? на самом деле вам не нужен был лучший способ, поскольку здесь есть лучшие ответы, вы просто хотели получить код, не думая о своей проблеме. Ты обречен на невежество, мальчик. - person Flavius; 09.02.2011
comment
Код в настоящее время не работает. Второй параметр array_key_exists должен быть массивом, а не значением. Foreach также необходимо изменить, чтобы получить ключ, а не значение (хотя, вероятно, лучше всего использовать array_keys). - person mpdonadio; 09.02.2011

При длине 12 цифр я не думаю, что вероятность получения повторов очень велика. Я бы, вероятно, просто сгенерировал числа, попытался бы вставить их в таблицу, и, если он уже существует (при условии, что у вас есть уникальное ограничение для этого столбца), просто сгенерируйте еще одно.

person Eric Petroelje    schedule 09.02.2011
comment
Мне было скучно, поэтому я хотел посмотреть, насколько это вероятно. Даже НЕ БЛИЖАЙШЕЕ к вероятности. При максимальном рандоме около 2 миллиардов. Я сгенерировал около миллиона случайных чисел и ни разу не столкнулся. У меня закончилась память, прежде чем я успел это сделать. ideone.com/fpnZX - person profitphp; 09.02.2011

Прочтите, например, 40000 (= PHP_INT_SIZE * 10000) байт из /dev/random сразу, затем разделите его, разбейте на модули (оператор %), и вот оно.

Затем отфильтруйте и повторите процедуру.

Это позволяет избежать слишком большого количества системных вызовов / переключений контекста (между средой выполнения php, движком zend и самой операционной системой - я не буду здесь вдаваться в подробности).

Это должен быть наиболее эффективный способ сделать это.

person Flavius    schedule 09.02.2011
comment
+1 - Мне нравится идея использовать /dev/random. Меня беспокоит только переносимость. Очевидно, это не будет работать с окнами и может не работать, если действует open_basedir ограничение. - person Eric Petroelje; 09.02.2011
comment
Я согласен. Вопрос не упоминает никаких ограничений, так что у меня была своя комната. - person Flavius; 09.02.2011
comment
У вас никогда раньше не было необходимости делать это, какой самый кошерный способ привести четырехбайтовый фрагмент к типу int (то есть в PHP)? - person mpdonadio; 09.02.2011
comment
unpack() - это путь. Как вы понимаете, производительность на всем пути с моим методом. У вас есть повторитель, поэтому в среде выполнения PHP нет циклов, циклы выполняются ЦП напрямую (через двоичный файл PHP). - person Flavius; 12.02.2011
comment
@Flavius ​​Sweet, я не знал об этой функции. - person mpdonadio; 14.02.2011
comment
Я тестировал это довольно много раз, но никогда /dev/urandom не возвращал мне хотя бы один повторяющийся номер из этих 10000. /dev/random хотя и медленный. Я могу отредактировать свой ответ, если вы хотите увидеть POC. Никаких циклов, только чистая скорость - по крайней мере, на стороне PHP. - person Flavius; 14.02.2011

Сгенерируйте 10000 случайных чисел и поместите их в массив. Пропустите массив через array_unique. Проверьте длину. Если меньше 10000, добавьте еще несколько штук. Пропустить массив через array_unique. Если больше 10000, то пробегите array_slice, чтобы получить 10000. В противном случае вспенить, промыть, повторить.

person mpdonadio    schedule 09.02.2011