Question

I want to generate 2000 unique random numbers between range 1000 and 9999. I'm doing something like this but it is not generating unique numbers.

$numbers = array();             

// Loop while there aren't enough numbers
while (count($numbers) < 2000) {

    $random_number = rand(1000, 9999);

    if (!in_array($random_number, $numbers)) {             
       // This adds the number to the array      
       $numbers[] = 'A'.$random_number.'14';
    }

}

Please help.

Was it helpful?

Solution 2

You check for the existance of a number, say 4567, but you add 'A456714', so you won't find the number.

You can fix it like this:

$numbers = array();             

// Loop while there aren't enough numbers
while (count($numbers) < 2000) {

    $random_number = rand(1000, 9999);

    $code = 'A'.$random_number.'14';

    if (!in_array($code, $numbers)) {             
       // This adds the number to the array      
       $numbers[] = $code;
    }

}

I must say, the solution by deceze is also very nice (nicer, actually). The difference is that in his solution, you won't have any double numbers at all to check for, so it's probably going to be faster most of the times.

The disadvantage is that you will have a relatively big array with 9000 numbers. For this specific situation, his solution might even be better, but if you select a smaller quantity of random numbers, or from a larger range, this (your own) solution might be better. If you want to select 100 random numbers from range(100, 1000000) then this solution is probably better, since the chance of picking a double number is very small and checking it is quite lightweight.

It's hard to tell where the tipping point is, but for your current situation, I would pick his.

OTHER TIPS

Instead of running many random tries, for a small range such as this I'd rather use this approach:

$candidates = range(1000, 9999);
shuffle($candidates);
$numbers = array_slice($candidates, 0, 2000);
$numbers = array_map(function ($number) { return "A{$number}14"; }, $numbers);

Rather than checking the array for whether the number already exists, try this:

<?php

$numbers=array();

while (count($numbers)<2000)
{
    $numbers['A'.rand(1000,9999).'14']=true;
}

$unique=array_keys($numbers);

echo print_r($unique,true).PHP_EOL;

It uses the fact that array keys are unique to remove the array checking. I would guess that counting the number of elements in an array is much quicker

It's because you added A and 14 to every number that you want to put in array $numbers.. So, the next loop for every number you generate there wont be any same number there..

Sorry for my broken English..

random.org API:

$numbers = explode(PHP_EOL,
    file_get_contents(
        'http://www.random.org/integers/?num=2000&min=1000&max=9999&col=1&base=10&format=plain&rnd=new'
    )
);


$numbers = array_map(function($v) {
    return 'A' . $v . '14';
}, $numbers);
function random_in_rang($min, $max, $count)
{
    $numbers = array();
    for($i=0; $i<$count; $i++)
    {
        //decrease range after adding a new random value
        $rnd = rand($min, $max-$count);
        //new value should be unique
        while(isset($numbers[$rnd])) $rnd++;
    }
    return array_keys($numbers);
}

A more efficient way (for speed and memory usage) for large range:

function get_unique_random_numbers($min,$max,$count) {
    $numbers = array();
    while( count($numbers) < $count ) {
          $numbers["A".mt_rand($min,$max)."14"] = 1;
    }
    return array_keys($numbers);
}

$numbers = get_unique_random_numbers(0,90000000,20000);
// < 0.X seconds

This method is more efficient when ($max-$min) >> $count. But it’s slow when ($max-$min) ~ $count. It make an infinite loop when ($max-$min) < $count.

So be careful. :) Eventually do a check before start the loop.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top