Perl: the Markov chain saw PerlMonks

### Re: How to generate distinct random numbers?

by Aristotle (Chancellor)
 on Sep 05, 2004 at 12:42 UTC Need Help??

in reply to How to generate distinct random numbers?

Just for the record, since everyone's talking about it but noone has shown any code:

```use List::Util qw( shuffle );

sub distinct_random_int {
my ( \$num, \$start, \$end ) = @_;
return if \$start > \$end or \$num > \$end - \$start + 1;
( shuffle \$start .. \$end )[ 0 .. \$num - 1 ];
}

Update: indeed, so long as the size of the range and the number of elements requested is within an order of magnitude, this is faster than the hash&retry solutions, in my tests by about 20%. If the discrepancy grows any larger, the hash&retry approach becomes much cheaper very quickly.

```use strict;
use warnings;

use Benchmark qw( cmpthese );
use List::Util qw( shuffle );

sub randseq_shuffle {
my ( \$num, \$start, \$end ) = @_;
return if \$start > \$end or \$num > \$end - \$start + 1;
( shuffle \$start .. \$end )[ 0 .. \$num - 1 ];
}

sub randseq_retry {
my ( \$num, \$start, \$end ) = @_;
return if \$start > \$end or \$num > \$end - \$start + 1;
my %seen;
my \$range = \$end - \$start;
my \$base = \$start;
undef \$seen{ \$base + int rand \$range } until \$num == keys %seen;
keys %seen;
}

for (
[ 5, 10, 30 ],
[ 50, 100, 300 ],
[ 500, 1000, 3000 ],
[ 5000, 10000, 30000 ],
[ 50000, 100000, 300000 ],
[ 5000, 10000, 30000 ],
[ 500, 10000, 30000 ],
[ 50, 10000, 30000 ],
[ 5, 10000, 30000 ],
) {
my ( \$n, \$s, \$e ) = @\$_;
cmpthese -1 => {
"shuffle(\$n,\$s,\$e)" => sub { randseq_shuffle \$n, \$s, \$e },
"retry(\$n,\$s,\$e)"   => sub { randseq_retry   \$n, \$s, \$e },
};
}

Makeshifts last the longest.

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://388596]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2024-02-26 13:33 GMT
Voting Booth?
My favourite way to spend a leap day ...

Results (25 votes). Check out past polls.