How can I generate an array in Perl with 100 random values, without using a loop?
I have to avoid all kind of loops, like \"for\", foreach\", while. This is my exerc
its ugly, but it works. the foreach is just to show that it does.
#!/usr/bin/perl
rand1();
$idx = 1;
foreach $item (@array) {
print "$idx - $item\n";
$idx++;
}
exit;
sub rand1() {
rand2();
rand2();
rand2();
rand2();
}
sub rand2() {
rand3();
rand3();
rand3();
rand3();
rand3();
}
sub rand3() {
push @array, rand;
push @array, rand;
push @array, rand;
push @array, rand;
push @array, rand;
}
The question: do something (and something happens to be call rand()
) a bunch of times without using a loop. Implied is, and without just repeating the source. None of the above answers actually answer this. They either repeat the source, or hide the looping. Here is a general approach that mitigates the repetition and does not hide looping (by implementing it using computed goto, or a regex, or recursion, etc). I call this approach "managed repetition."
100 has four prime factors: 2*2*5*5 == 100. So we need two repetition managers, five and two:
sub two{ my $y=shift; ($y->(), $y->()) }
sub five{my $y=shift; ($y->(), $y->(), $y->(), $y->(), $y->()) }
then call them -- we're not recursing, because the recursion degenerate case constitutes a loop test -- just calling them:
my @array = five(sub{five(sub{two(sub{two(sub{rand()})})})});
There you are, a general way to call something a predetermined number of times without using a loop, rather, by delegating the repetition in an efficient and controlled way.
Discussion question: which order should the fives and twos be in and why?
# I rolled a die, honestly!
my @random = (5, 2, 1, 3, 4, 3, 3, 4, 1, 6,
3, 2, 4, 2, 1, 1, 1, 1, 4, 1,
3, 6, 4, 6, 2, 6, 6, 1, 4, 5,
1, 1, 5, 6, 6, 5, 1, 4, 1, 2,
3, 1, 2, 2, 6, 6, 6, 5, 3, 3,
6, 3, 4, 3, 1, 2, 1, 2, 3, 3,
3, 4, 4, 1, 5, 5, 5, 1, 1, 5,
6, 3, 2, 2, 1, 1, 5, 2, 5, 3,
3, 3, 5, 5, 1, 6, 5, 6, 3, 2,
6, 3, 5, 6, 1, 4, 3, 5, 1, 2);
Recursion:
#!/usr/bin/perl
use warnings; use strict;
my @rands;
my $i=1;
sub push_rand {
return if $#rands>=99;
push @rands, rand;
push_rand();
}
push_rand();
for (@rands) { print "$i: $_\n"; $i++; }
Someone asked for a pure regex solution. How about
#!/usr/bin/perl
open my $slf, $0;
undef $/;
(my $s = <$slf>) =~ s/./rand()." "/eggs;
$s .= rand();
For amusement value:
#!/usr/bin/perl
use strict;
use warnings;
$/ = \1;
open 0;
my @r = map rand,<0>;
print "@r\n";
for
, while
, until
:#!/usr/bin/perl
use strict; use warnings;
my @rand;
NOTLOOP:
push @rand, rand;
sleep 1;
goto NOTLOOP if 100 > time - $^T;
print 0 + @rand, "\n";
#!/usr/bin/perl
use strict; use warnings;
my $s = '-' x 100;
$s =~ s/(-)/rand() . $1/eg;
my @rand = $s=~ m/([^-]+)/g;
rand
invocations by hand is really passé:#!/usr/bin/perl
use strict; use warnings;
my $s = '(' . 'rand,' x 100 . ')';
my @rand = eval $s;
/dev/random
:#!/usr/bin/perl
use strict; use warnings;
$/ = \1;
my @rand;
seek \*DATA, 0, 0;
NOTLOOP:
scalar <DATA>;
push @rand, rand;
goto NOTLOOP if $. < 100;
__DATA__
goto
#!/usr/bin/perl
use strict; use warnings;
use autodie;
$/ = \1;
open my $F, '<', \( 1 x 100 . 0 );
my @rand or ¬loop;
sub notloop {
my $t = <$F>;
$t or return;
push @rand, rand;
goto \¬loop;
}
eval
version:#!/usr/bin/perl
use strict; use warnings; use autodie;
local $/ = \1;
open my $F, '<', \( 1 x 100 . 0 );
my @rand;
eval <<'NOLOOP'
my $self = (caller(0))[6];
<$F> or die;
push @rand, rand;
eval $self;
NOLOOP
;
Of course, all of these actually do contain loops, but they do not use the keywords you were barred from using.
NB: This question has brought out the wacko in me, but I must admit it is amusing.