Re: How to not print the same random number
by bart (Canon) on Mar 04, 2006 at 10:34 UTC
|
A more efficient way to achieve what you want, is just to shuffle an array.
To make the concept clear, let me compare to a deck of cards. How do you prevent from drawing the same card twice? By not putting the card back in the deck before you draw another one.
You get the same result by simply shuffling the deck, and picking the next card, one by one.
shuffle is a function you can find in List::Util. You use it like this:
use List::Util 'shuffle';
my @shuffled_deck = shuffle 1 .. 10;
local $\ = "\n";
foreach(@shuffled_deck) {
print;
}
I get, for example, the following output:
1
2
9
8
7
10
4
5
6
3
It'll be far more efficient than retrying until you get something you haven't seen before, especially near the end, when you've almost seen them all. | [reply] [d/l] [select] |
Re: How to not print the same random number
by borisz (Canon) on Mar 04, 2006 at 10:28 UTC
|
perl -MList::Util=shuffle -e 'print "@{[shuffle(1..10)]}"'
| [reply] [d/l] |
|
|
| [reply] |
|
|
Yes sure, the array with all numbers is build and shuffled. On the other hand, hash solutions require more memory and more cpu power they build the same array but slower. A hash is a better choice, if you use only some number out of a large range. For really really much numbers a database is my best choice.
| [reply] |
|
|
|
|
Not much of a hog. Storing the numbers already picked in a hash would be about as bad. (I'm not sure how many copies of the list the shuffle approach will end up having.)
But anyway, if you go with what I understand to be your idea of
repeatedly generating random numbers until you find one not yet in a hash, you'll end up taking a very very long time finding the last few numbers if the limit is, say, 1000000.
| [reply] |
|
|
|
|
The question becomes "are you going to use all the numbers in that range?" If so, you have to remember them all regardless of your approach. If no, then you could save memory by just tracking what you use... but this then becomes more processor-expensive.
| [reply] |
|
|
Re: How to not print the same random number
by GrandFather (Saint) on Mar 04, 2006 at 11:05 UTC
|
use strict;
use warnings;
my @numbers = 1..10;
print splice (@numbers, rand (@numbers), 1), "\n" while @numbers;
DWIM is Perl's answer to Gödel
| [reply] [d/l] |
Re: How to not print the same random number
by shotgunefx (Parson) on Mar 04, 2006 at 09:21 UTC
|
| [reply] |
Re: How to not print the same random number
by GrandFather (Saint) on Mar 04, 2006 at 11:02 UTC
|
use strict;
use warnings;
print join"\n",grep$_,map{our%s;my$n=1+int rand(10);$s{$n}++?0:$n}1..1
+00;
DWIM is Perl's answer to Gödel
| [reply] [d/l] |
|
|
I like the "may" part. Did you calculate the actual odds?
| [reply] |
|
|
| [reply] |
Re: How to not print the same random number
by spiritway (Vicar) on Mar 04, 2006 at 11:46 UTC
|
If you're excluding numbers, it's not random. For example, if you've already chosen 9 numbers, the tenth is completely determined. FWIW.
| [reply] |
Re: How to not print the same random number
by TedPride (Priest) on Mar 04, 2006 at 15:12 UTC
|
The following should achieve pretty random results within the constraints you asked for - 10 unique numbers from 1-10 sorted randomly.
@arr = 1..10;
randomize(\@arr);
print "@arr";
sub randomize {
my ($p, $size, $swap, $key);
$p = $_[0];
$size = $#$p;
for (0..($size-1)) {
$swap = int rand($size - $_ + 1) + $_;
$key = $p->[$_];
$p->[$_] = $p->[$swap];
$p->[$swap] = $key;
}
}
| [reply] [d/l] |
|
|
($p->[$_], $p->[$swap]) = ($p->[$swap], $p->[$_]);
Note though that it is slower:
use strict;
use warnings;
use Benchmark qw(cmpthese);
my @arr = 1..2;
cmpthese (-1,
{
temp => sub {my $temp = $arr[0]; $arr[0] = $arr[1]; $arr[1
+] = $temp;},
swap => sub {($arr[0], $arr[1]) = ($arr[1], $arr[0]);},
}
);
Rate swap temp
swap 1381331/s -- -43%
temp 2425611/s 76% --
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: How to not print the same random number
by TedPride (Priest) on Mar 04, 2006 at 17:42 UTC
|
## Assign the numbers 1-10 to array @arr
@arr = 1..10;
## Pass @arr by reference to function randomize()
randomize(\@arr);
## When used in this context, the array prints
## with space delimiters between items
print "@arr";
sub randomize {
## Declare variables inside the scope of
## this function
my ($p, $size, $swap, $key);
## Assign the array reference passed to
## the function to $p
$p = $_[0];
## Assign the length of the array pointed
## to by $p to $size. This is the number
## of items in the array - 1
$size = $#$p;
## Randomize all items up to the next to
## last item. The last item is randomized
## already if the other items are.
for (0..($size-1)) {
## Pick a random item from current
## position to end
$swap = int rand($size - $_ + 1) + $_;
## Swap item with current position
$key = $p->[$_];
$p->[$_] = $p->[$swap];
$p->[$swap] = $key;
}
}
You should probably look up $_ and @_ and read up on references, it will help you understand this a bit. | [reply] [d/l] |
Re: How to not print the same random number
by cognizant (Pilgrim) on Mar 04, 2006 at 10:39 UTC
|
use Data::Random qw(:all);
my @random_chars = rand_chars( set => 'numeric', min => 10, max => 10
+);
foreach (@random_chars)
{print "$_\n";}
--C | [reply] [d/l] |