perl -MList::Util=shuffle -e 'print "@{[shuffle(1..10)]}"'
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.
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.
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 [cpan://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.
use Data::Random qw(:all);
my @random_chars = rand_chars( set => 'numeric', min => 10, max => 10 );
foreach (@random_chars)
{print "$_\n";}
--C
use Data::Random qw(:all);
my @random_chars = rand_chars( set => 'numeric', min => 10, max => 10 );
foreach (@random_chars)
{print "$_\n";}
--C
This may give you what you want:
use strict;
use warnings;
print join"\n",grep$_,map{our%s;my$n=1+int rand(10);$s{$n}++?0:$n}1..100;
Statistics is not my strong suit. I ran a test version a few times and noticed that about 23-25 itterations sufficed often enough and guessed that 100 would seldom dissapoint. Glad you noticed the "may". :)
or you could just pull numbers out at random then throw them away:
use strict; use warnings; my @numbers = 1..10; print splice (@numbers, rand (@numbers), 1), "\n" while @numbers;
If you're excluding numbers, it's not random. For example, if you've already chosen 9 numbers, the tenth is completely determined. FWIW.
@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;
}
}
You can eliminate the manifest temporary by:
($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% --
## 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.
perlmonks.org content © perlmonks.org and acid06, Anonymous Monk, bart, borisz, cognizant, fishbot_v2, GrandFather, shotgunefx, spiritway, TedPride, ysth
prlmnks.org © 2006 edmund von der burg (eccles & toad)
v 0.03