There's more than one way to do things PerlMonks

### Non-Repetitive Random Numbers

 on Apr 05, 2013 at 05:34 UTC Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks

I need to generate non-repetitive random numbers. I have looked into the rand() function but it gives repeating numbers. Searching for answers I came across script which implements it through a hash which is as follows:

```sub rand_sam {
my (\$n,@n) = (shift,@_);
return 0 unless (\$n < scalar @n);
my %seen = ();
until (keys %seen == \$samples) {
\$seen{\$pop[rand @pop]}=1;
}
return(keys %seen);
}
[download]```

But could not understand the script. Please suggest ways to efficiently generate non repetitive random numbers(from 0 to 100000)..

THnx..

Replies are listed 'Best First'.
Re: Non-Repetitive Random Numbers
by kcott (Chancellor) on Apr 05, 2013 at 06:00 UTC

Here's a technique to generate non-repetitive random numbers:

```\$ perl -Mstrict -Mwarnings -E '
my @nums = 0 .. 100000;
say splice @nums, int(rand @nums), 1 for 1 .. 10;
'
[download]```

Sample output:

```10228
67730
84390
58034
22572
34234
43334
38920
5934
82290
[download]```

Depending on how you want to use this, you may need to check whether @nums becomes exhausted.

The "script" you provided is only a subroutine. You don't show the context in which it is called; you don't show how the global variable \$samples is declared or what sort of value(s) are assigned to it. An explanation of the "script" will actually require the script.

-- Ken

The full script is as follows:

```my @pop = (1..100);
my \$samples = 30;
my @sample = rand_samp(30,@pop);
print "@sample";

sub rand_samp {
my (\$n,@n) = (shift,@_);
return 0 unless (\$n < scalar @n);# see note below
my %seen = ();
until (keys %seen == \$samples) {
\$seen{\$pop[rand @pop]}=1;
}
return(keys %seen);
}
[download]```
Re: Non-Repetitive Random Numbers
by hdb (Monsignor) on Apr 05, 2013 at 06:33 UTC

The List::Util module provides a function to shuffle a list which seems most suitable for the task.

```use strict;
use warnings;
use List::Util qw( shuffle );
my @random = shuffle 0..99999;
print join "\n", @random[0..9];
[download]```
Re: Non-Repetitive Random Numbers
by BrowserUk (Pope) on Apr 05, 2013 at 13:10 UTC

The problem with most of the solutions offered is that they create a list the size of the range of numbers required (100,000) in order to obtain the sample of 30 values. Many compound that by additionally creating an array and a hash.

Not so bad whilst the range is in the 100s of thousands but once you need a range in the 10s of millions or more, your going to run out of memory pretty quick in order to create those 30 values.

This will produce as many unique values (in a random order) as you wish to fetch for any range upto 4 billion, whilst never consuming more than 512MB. (and considerably less for smaller ranges. eg. 0-100,000 will use < 13kB.)

```sub uniqRands {
state \$vec = '';
\$vec = '' if @_ == 2;
my \$n;
1 while vec( \$vec, \$n = int( rand \$_[0] ), 1 );
vec( \$vec, \$n, 1 ) = 1;
return \$n;
}

my @sample = map uniqRands( 100_000 ), 1 .. 30;
[download]```

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
What, you're limited to 0..4294967295, this sucks!

Just kidding, this solution is awesome :-)

-- Time flies when you don't know what you're doing
Re: Non-Repetitive Random Numbers
by AnomalousMonk (Chancellor) on Apr 05, 2013 at 07:28 UTC

I am by no means an initiate of the Dark Mysteries™ of random numbers (Update: see reply below of BrowserUk), but here's a possibly interesting use of an iterator:

```>perl -wMstrict -le
"use List::Util qw(shuffle);
;;
sub Iterator (&) { return \$_[0]; }
;;
sub rand_iter {
my \$total = shift;
;;
my \$random = [ shuffle 0 .. \$total-1 ];
;;
return Iterator {
my \$n = shift;
return if \$n < 0 or \$n > @\$random;
return splice @\$random, 0, \$n;
}
}
;;
my \$iter = rand_iter(9);
;;
use Data::Dump;
dd [ \$iter->(0) ];
dd [ \$iter->(5) ];
dd [ \$iter->(4) ];
dd [ \$iter->(1) ];
dd [ \$iter->(2) ];
"
[]

[5, 4, 0, 2, 8]

[7, 3, 6, 1]

[]

[]
[download]```
Re: Non-Repetitive Random Numbers
by Rahul6990 (Beadle) on Apr 05, 2013 at 05:54 UTC
Re: Non-Repetitive Random Numbers
by FloydATC (Deacon) on Apr 05, 2013 at 12:45 UTC
This is semantics, but random numbers may be repetitive or not, or they're not truly random. If what you really want is a sequence 1..100000 in random order then Perl can do that for you:
```use List::Util;
@shuffled = List::Util::shuffle(1..100000);
[download]```

-- Time flies when you don't know what you're doing
Re: Non-Repetitive Random Numbers
by LanX (Bishop) on Apr 05, 2013 at 14:08 UTC
maybe I'm blind, but I'm missing the simplest approach ...

```  DB<109> %seen=();

DB<110> \$seen{int rand 10000}=1 while (keys %seen <10)

DB<111> keys %seen
=> (4402, 3312, 9339, 1345, 3461, 9357, 1185, 4646, 6571, 1315)
[download]```

... and I don't think it's less efficient than the others.

Cheers Rolf

( addicted to the Perl Programming Language)

That doesn't guarantee unique values. With the built-in rand/srand, it produces repeats within 30 picks for seeds:

```seed : no.of picks before repeat
89 : 12
178 : 17
485 : 9
504 : 14
555 : 22
662 : 16
688 : 23
761 : 19
766 : 18
920 : 26
936 : 25
943 : 19
955 : 17
982 : 14
1004 : 27
1032 : 19
1192 : 23
1200 : 9
1385 : 24
1427 : 17
1439 : 29
1459 : 22
1582 : 14
1593 : 22
1602 : 29
1668 : 12
1737 : 22
1924 : 29
1933 : 24
1969 : 18
2186 : 27
2261 : 12
2297 : 12
2380 : 18
2410 : 29
2660 : 25
2690 : 28
2733 : 24
2817 : 13
2863 : 4
2875 : 19
2964 : 28
3023 : 27
3052 : 9
3198 : 24
3208 : 23
3240 : 28
3292 : 16
3415 : 2
3529 : 26
3669 : 22
3692 : 29
3741 : 21
3754 : 13
3791 : 23
3805 : 28
3842 : 24
3854 : 8
3956 : 28
4077 : 27
4202 : 20
-- More  --

[download]```

Testcase:

```#! perl -slw
use strict;

for my \$i ( 1 .. 100000 ) {
my %hash;
srand \$i;
++\$hash{ int rand 100000 } == 2 and print "\$i : ", scalar keys %ha
+sh
while keys %hash < 30;
}
[download]```

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
I don't understand your point (and I'm too much in a hurry ATM to investigate your code)

Keys of a hash are always unique, in my code collisions of random numbers are simply ignored.

##### update

> That doesn't guarantee unique values.

maybe this is clearer:

```  DB<107> \$seen{int rand 10}=1 for 1 .. 1000000
=> ""

DB<108> keys %seen
=> (6, 3, 7, 9, 2, 8, 1, 4, 0, 5)
[download]```

##### update
one could argue that the order of hash -keys isn't random but that wasn't part of the question.

Otherwise thats a good occasion to use shuffle or pushing into an array (but this implies reseeding rand every time)

Cheers Rolf

( addicted to the Perl Programming Language)

Re: Non-Repetitive Random Numbers
by pemungkah (Priest) on Apr 06, 2013 at 10:22 UTC
Re: Non-Repetitive Random Numbers
by 2teez (Vicar) on Apr 05, 2013 at 05:42 UTC

Please take a look at perl function srand.
This function "seed" the rand function so that rand can produce a different sequence each time you run your program.

If you tell me, I'll forget.
If you show me, I'll remember.
if you involve me, I'll understand.
--- Author unknown to me
Please take another look at the documentation you linked to.

The docs for rand state that it "Automatically calls srand unless srand has already been called." It is not necessary to call srand manually and doing so may actually reduce the randomness of the sequence your receive. (If you call srand repeatedly, it will almost certainly do so.)

Log In?
 Username: Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1027065]
Approved by marto
help
Chatterbox?
and a log crumbles through the grate...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2018-05-28 04:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
World peace can best be achieved by:

Results (199 votes). Check out past polls.

Notices?