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 exercise, from my lab. I can't find a way to do solve this, because I am new in Perl.
In C, generating this array would by very easy, 开发者_StackOverflow社区but I don't know how to do it in Perl.
For amusement value:
A method that works on systems where EOL is a single character:
#!/usr/bin/perl
use strict;
use warnings;
$/ = \1;
open 0;
my @r = map rand,<0>;
print "@r\n";
A possibly nondeterministic method that does not use 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";
Using regular expressions:
#!/usr/bin/perl
use strict; use warnings;
my $s = '-' x 100;
$s =~ s/(-)/rand() . $1/eg;
my @rand = $s=~ m/([^-]+)/g;
Copying and pasting 100 rand
invocations by hand is really passé:
#!/usr/bin/perl
use strict; use warnings;
my $s = '(' . 'rand,' x 100 . ')';
my @rand = eval $s;
A file I/O based solution that does not require /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__
No reason to use recursion with Perl's 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;
}
Here is a recursive string 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.
Nothing could be simpler!
my @rands = (rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand, rand, rand, rand, rand, rand, rand, rand, rand, rand,
rand, rand);
Pure Regex Solution
perl -E'say for&{sub{"\U\x{fb01}\x{fb03}"=~/.{0,2}.{0,3}.{0,3}.{0,4}+(?{$_[++$#_]=rand})(*FAIL)/||pop;@_}}'
Double‐/e
Regex Solution
This:
($_=(120.44.32)x(2+2*2**2)**2)=~s/\170/114.97.110.100/gee;
s/(.*)/64.95.61.40.$1.41.35.89.65.78.69.84.85.84/ee;
print "@_\n";
looplessly produces this:
0.636939813223766 0.349175195300148 0.692949079946754 0.230945990743699 0.61873698433654 0.940179094890468 0.435165707624346 0.721205126535175 0.0322560847184015 0.91310500801842 0.31596325316222 0.788125484008084 0.802964232426337 0.417745170032291 0.155032810595454 0.146835982654117 0.181850358582611 0.932543988687968 0.143043972615896 0.415793094159206 0.576503681784647 0.996621492832261 0.382576007897708 0.090130958455255 0.39637315568709 0.928066985272665 0.190092542303415 0.518855656633185 0.797714758118492 0.130660731025571 0.534763929837762 0.136503767441518 0.346381958112605 0.391661401050982 0.498108766062398 0.478789295276393 0.882380841033143 0.852353540653993 0.90519922056134 0.197466335156797 0.820753004050889 0.732284103461893 0.738124358455405 0.250301496672911 0.88874926709342 0.0647566487704268 0.733226696403218 0.186469206795884 0.837423290530243 0.578047704593843 0.776140208497122 0.375268613243982 0.0128391627800006 0.872438613450569 0.636808174464274 0.676851978312946 0.192308731231467 0.401619465269903 0.977516959116411 0.358315250197542 0.726835710856381 0.688046044314845 0.870742340556202 0.58832098735666 0.552752229159754 0.170767637182252 0.683588677743852 0.0603160539059857 0.892022266162105 0.10206962926371 0.728253338154527 0.800910562860132 0.628613236438159 0.742591620029089 0.602839705915397 0.00926448179027517 0.182584549347883 0.53561587562946 0.416667072500555 0.479173194613729 0.78711818598828 0.017823873107119 0.824805088282755 0.302367196288522 0.0677539595682397 0.509467036447674 0.906839536492864 0.804383046648944 0.716848992363769 0.450693083312729 0.786925293921154 0.078886787987166 0.417139859647296 0.9574382550514 0.581196777508975 0.75882630076142 0.391754631502298 0.370189654004974 0.80290625532508 0.38016959549288
Recursive Numeric Function Solution
As in fact, does this, if you print the array:
@_=(*100=sub{$_[0]?(rand,(*{--$_[0]}=*{$_[0]})->(@_)):()})->($==100);
The second solution now allows for getting different numbers of random numbers easily enough, since following the assignment above, you can do such niceties as:
print for @42=42->($==42);
And yes, that is indeed a function named 42()
. The previous assignment to @_
created it along with a hundred other numerically named functions.
Explanation
The first regex solution relies on Unicode’s tricky casing of the two characters matched against. It may (or may not) be more easily understood with whitespace and comments added:
use 5.010;
say for &{
sub { "\U\x{fb01}\x{fb03}" =~ m((?mix-poop)
#include <stdlib.h>
#include <unistd.h>
#include <regex.h>
#include "perl.h"
#include "utf8.h"
#ifndef BROKEN_UNICODE_CHARCLASS_MAPPINGS
.{0,2}
.{0,3} .{0,3}
.{0,4}
#define rand() (random()<<UTF_ACCUMULATION_SHIFT^random()&UTF_CONTINUATION_MASK)
+(?{ $_ [++$#_] = rand() || rand() || UTF8_TWO_BYTE_LO (*PERL_UNICODE)
#else (*PRUNE)
#define FAIL (*ACCEPT)
}) (*FAIL)
#endif (*COMMIT)
)poop || pop @{ (*_{ARRAY}) }
;#; @{ (*SKIP:REGEX) }
@{ (*_{ARRAY}) }
}
}
The way to understand how the second regex solution works is:
- First, reduce the compile-time constant expressions into their more customary forms so you can more easily read the literals. For example,
\170
is "x". - Second, trim down the double
e
to a singlee
in each substitution, then print out what that leaves in the string both times.
I’m sure you’ll appreciate the comment. :)
For the recursive solution, adding whitespace may help a little:
(*100 = sub { $_[0]
? ( rand, ( *{ --$_[0] } = *{ $_[0] } )->(@_) )
: ( )
}
)->( $= = 100 );
The need to pass a variable as an argument is due to the auto-decrement requiring an lvalue. I did that because I didn’t want to have to say $_[0] - 1
twice, or have any named temporary variables. It means you can do this:
$N = 100;
print for $N->($N);
And when you’re done, $N == 0
, because of pass‐by‐implicit‐reference semantics.
For the cost of a bit of repetition, you can relax the need of an lvalue argument.
(*100 = sub { $_[0]
? ( rand, ( *{ $_[0] - 1 } = *{ $_[0] } )->( $_[0] - 1 ) )
: ( )
}
)->( 100 );
Now you no longer need an lvalue argument, so you can write:
print for 100->(100);
to get all 100 random numbers. Of course, you also have a hundred other numeric functions, too, so you can get lists of random numbers in any of these ways:
@vi = 6->(6);
@vi = &6( 6);
$dozen = 12;
@dozen = $dozen->($dozen);
@baker's_dozen = &$dozen(++$dozen);
@_ = 100;
print &0; # still a hundred of 'em
(Sorry ’bout the silly colors. Must be an SO bug.)
I trust that clears everything up. ☺
my @rand = map { rand } ( 1..100 );
But a map is just a loop with fancy window-dressing.
If you need to do something 100 times, you're going to need to use some kind of iterative structure.
# 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);
Too bad most of the solutions focused on the non-looping part and neglected the random numbers part. Some of you may not be old enough to have a printed table of random values (or an appendix of logarithms) in the back of your engineering textbooks. It's all online now:
use LWP::Simple;
my @numbers = split /\s+/, #/ Stackoverflow syntax highlighting bug
get( 'http://www.random.org/integers/?num=100&min=1&max=100&col=1&base=10&format=plain&rnd=new' );
Here's the insanity that Tom was waiting to see, but I make it slightly more insane. This solution reduces the problem to a rand
call:
my @numbers = rand( undef, 100 ); # fetch 100 numbers
Normal rand normally takes 0 or 1 arguments. I've given it a new prototype that allows a second argument to note how many numbers to return.
Notice some differences to the real rand
though. This isn't continuous, so this has far fewer available numbers, and it's inclusive on the upper bound. Also, since this one takes two arguments, it's not compatible with programs expecting the real one since a statement like this would parse differently in each:
my @array = rand 5, 5;
However, there's nothing particularly special about CORE::GLOBAL::rand()
here. You don't have to replace the built-in. It's just a bit sick that you can.
I've left some print
statements in there so you can watch it work:
BEGIN {
my @buffer;
my $add_to_buffer = sub {
my $fetch = shift;
$fetch ||= 100;
$fetch = 100 if $fetch < 100;
require LWP::Simple;
push @buffer, split /\s+/, #/ Stackoverflow syntax highlighting bug
LWP::Simple::get(
"http://www.random.org/integers/?num=$fetch&min=1&max=100&col=1&base=10&format=plain&rnd=new"
);
};
my $many = sub ($) {
print "Fetching $_[0] numbers\n";
$add_to_buffer->($_[0]) if @buffer < $_[0];
my @fetched = splice @buffer, 0, $_[0], ();
my $count = @fetched;
print "Fetched [$count] @fetched\n";
@fetched
};
*CORE::GLOBAL::rand = sub (;$$) {
my $max = $_[0] || 1; # even 0 is 1, just like in the real one
my $fetch = $_[1] || ( wantarray ? 10 : 1 );
my @fetched = map { $max * $_ / 100 } $many->( $fetch );
wantarray ? @fetched : $fetched[-1];
};
}
my @rand = rand(undef, 5);
print "Numbers are @rand\n\n";
@rand = rand(87);
print "Numbers are @rand\n\n";
$rand = rand(undef, 4);
print "Numbers are $rand\n\n";
$rand = rand();
print "Numbers are $rand\n\n";
$rand = rand(undef, 200);
print "Numbers are $rand\n\n";
My source of random numbers isn't important for this technique though. You could read from /dev/random or /dev/urandom to fill the buffer if you like.
sub f {
my $n = shift;
if( $n == 0 ) {
return @_;
}
else {
return f( $n-1, rand, @_ );
}
}
my @random_array = f(100);
Since the task seems to be either to get you to use recursion or to learn how to write an easy loop in a not-so-easy form, humbly I submit the following FULLY EXECUTABLE Perl programs:
Camel:
#!/usr/bin/perl
''=~('('.'?'
.'{'.( '`'|'%').("\["^
'-').('`'| '!').('`'|',').'"'
.'\\'.'$'. ("\`"| ',').('`'|')').('`'|
'-').'='.('^'^("\`"| '/')).('^'^('`'|'.')).
('^'^('`'|'.')).';'.( '!'^'+').('`'|'&').('`'
|'/').('['^')').'(' .'\\'.'$'.'='.'='.(('^')^(
'`'|'/')).';'. '\\'.'$'.'='.'<'.'='.'\\'.'$'
.('`'|(',')).( '`'|')').('`'|'-').';'.'+'."\+".
'\\'.'$'.('='). ')'.'\\'.'{'.('['^'+').('['^"\.").(
'['^'(').("\`"| '(').('{'^'[').'\\'.'@'.'='.','.("\{"^
'[').('['^')'). ('`'|'!').('`'|'.').('`'|'$').'\\'.'}'.(
'!'^'+').'\\'. '$'.'='.'='.('^'^('`'|'/')).';'.('!'^'+')
.('`'|('&')).( '`'|'/').('['^')').('{'^'[').'('.'\\'.'@'.
'='.')'.('{'^'[').'\\'.'{'.('!'^'+').('*'^'#').('['^'+').(
'['^')').('`'|')').('`'|'.').('['^'/').('{'^'[').'\\'.'"'.(
'['^')').('`'|'!').('`'|'.').('`'|'$').('{'^'[').'\\'.'$'.
'='.('{'^'[').('`'|'/').('`'|'&').('{'^'[').'\\'.'$'.("\`"|
',').('`'|')').('`'|'-').'='.'\\'.'$'.'_'.'\\'.'\\'.(('`')|
'.').'\\'.'"'.';'.('!'^'+').('*'^'#').'\\'.'$'.'='.'+'.'+'
.';'.('!'^'+').('*'^'#').'\\'.'}'.'"'.'}'.')');$:='.' ^((
'~'));$~='@'|'(';$^=')'^'[';$/='`'|'.';$,='('^"\}"; $\=
'`'|'!';$:=')'^'}';$~='*'|'`';$^='+'^'_'; $/="\&"| '@'
;$,='['&'~';$\=','^'|';$:='.'^"\~";$~= '@'|'(' ;$^
=')'^ '[';$/='`'|'.';$,='('^"\}";$\= '`'|'!' ;$:
=')'^'}';$~='*'|'`';$^=('+')^ '_';$/= '&'
|'@';$,= '['&'~';$\ ="\,"^ '|';$: =(
('.'))^ "\~";$~= ('@')| '(';$^ =(
(')'))^ "\[";$/= "\`"| "\."; (
($,))= '('^'}'; ($\) ='`'
|"\!"; $:=(')')^ '}'; ($~)
='*'| "\`";$^= '+'^ '_';
($/)= '&'|'@' ;$,= '['&
'~'; $\=',' ^'|' ;$:=
'.'^ '~' ;$~= '@'|
'('; $^= ')' ^((
'[' )); $/= '`'
|(( '.' )); $,=
'(' ^(( '}' ))
;( ($\))= ((
(( '`')) ))
|+ "\!";$:= ((
')' ))^+ "\}"; $~
=(( '*'))| '`'; $^=
'+'^ "\_";$/= '&' |'@'
;($,)= ('[')&
"\~";$\= ','^'|'
Martini:
#!/usr/bin/perl
''=~('(?{'.
('`'|'%').(
'['^"\-").(
'`'|"\!").(
'`'|(',')).
'"\\$'.('`'
|',').(
'`'|')'
).('`'|
('-')).
('=').(
'^'^('`'|
('/'))).(
'^'^('`'|
('.'))).(
'^'^(('`')|
'.')).';'.(
'!'^'+').('`'
|'&').(('`')|
'/').('['^')').
'(\\$=='.('^'^(
'`'|'/')).';\\$='
.'<=\\$'.('`'|',').
('`'|')').('`'|"\-").
';++\\$=)\\{'.('['^'+')
.('['^'.').('['^'(').('`'
|'(').('{'^'[').'\\@'.('`'|
'!').('['^')').('['^"\)").(
'`'|'!').('['^'"').','.('{'
^'[').('['^')').('`'|'!').(
'`'|'.').('`'|"\$").'\\}'.(
'!'^'+').'\\$'.('`'|')').'='.("\^"^( '`'|'/')).';'.('!'^('+')).(
'`'|'&').('`'|'/').('['^')').('{'^ '[').'(\\@'.('`'|'!').('['^
')').('['^')').('`'|'!').('['^ '"').')'.('{'^"\[").'\\{'.(
'!'^'+').('*'^'#').('['^'+') .('['^')').('`'|')').("\`"|
'.').('['^'/').('{'^'[') .'\\"'.('['^')').('`'|'!').
('`'|'.').('`'|"\$").( '{'^'[').'\\$'.('`'|"\)").(
'{'^'[').('`'|'/') .('`'|'&').('{'^'[').'\\$'.
('`'|',').("\`"| ')').('`'|'-').'=\\$_\\\\'.
('`'|('.')). '\\";'.('!'^'+').('*'^'#').
'\\$'.('`' |')').'++;'.('!'^'+').('*'^
"\#"). '\\}"})');$:='.'^'~';$~='@'
|'(' ;$^=')'^'[';$/='`'|"\.";$,=
'('^ '}';$\='`'|'!';$:=')'^"\}";
($~) ='*'|'`';$^='+'^'_';$/='&'|
'@'; $,='['&'~';$\=','^('|');$:=
'.'^ '~';$~='@'|'(';$^=')'^"\[";
($/) ='`'|'.';$,='('^'}';$\='`'|
'!'; $:=')'^'}';$~='*'|('`');$^=
'+'^ '_';$/='&'|'@';$,='['&"\~";
($\) =','^'|';$:='.'^'~';$~='@'|
'('; $^=')'^'[';$/='`'|('.');$,=
'('^ '}';$\='`'|'!';$:=')'^"\}";
($~) ='*'|'`';$^='+'^'_';$/='&'|
'@';$,='['&'~';$\=','^'|';$:='.'^'~' ;$~='@'|'(';$^=')'^"\[";$/=
'`'|'.';$,='('^'}';$\='`'|'!';$:=')' ^'}';$~='*'|'`';$^='+'^'_';
For the Holidays, snowflakes with recursion rather than iteration inside:
#!/usr/bin/perl
'?' =~(
'('.'?' ."\{".(
'`' |'%' ).('['^"\-").( '`'| '!'
).('`'|','). '"'. '\\'.('$').(
'`'|(',')).( '`'| ')').(('`')|
(( '-') )). +( '`' |')' ).
((( '[' ))^+ (( '/') )). '='
.('^'^ ('`'|'/')) .( '^'^("\`"| '.')).
+( '^'^('`'|'.')).';'.('!'^"\+"). ((
'\\')).'$'.('`'|'#').('`'|'/').('['^'.').('`'|'.').(
'['^ '/').'='. (('^')^( '`'|'/') ).(';').( '!'^
'+' ).('['^ '(').( ('[')^ "\.").( '`'
|'"' ).(('{')^ ('[')).( '['^'+') .('['^'.' ).+(
'['^'(').('`'|'(').'_'.('['^')').('`'|'!').('`'|'.')
.( '`'|'$').('{'^'[').'\\'."\{".( ((
'!'))^ '+').('{'^ (( ('[')))).( ('{')^
'[' ).( '{'^ (( '[') )). (((
(( '{') ))) ^+ '[' ).+( ((
'['))^')').( '`'| '%').(('[')^
'/').(('[')^ '.') .('['^')').(
'`' |'.' ).('{'^"\[").( '`'| ')'
).('`'| "\&").(
'{' ^((
'[' )))
.'\\'.+ '$'.'#'
.+( '`'| '!').('['^')') .''. (((
'['))^')').( '`'| '!').(('[')^
'"').('_').( '`'| '/').(('`')|
(( '&') )). (( '_' )).( ((
'[' ))^ ')') .( '`'| '!' ).(
('`')| '.').('`'| (( ('$')))).( ('[')^
(( '('))).'>'.'\\'.'$'.('`'|','). +(
'`'|')').('`'|'-').('`'|')').('['^'/').';'.('!'^'+')
.''. ('{'^'[') .(('{')^ ('[')).( '{'^'['). ('{'
^(( '['))). ("\["^ '+').( '['^'.' ).(
'['^ '(').('`' |"\(").( '{'^'[') .'\\'.'@' .''.
('`'|'!').('['^')').('['^')').('`'|'!').('['^('"')).
(( '_')).('`'|'/').('`'|'&').'_'. +(
('[')^ ')').('`'| (( ('!')))).( ('`')|
'.' ).( '`'| (( '$') )). (((
(( '[') ))) ^+ '(' ).(( ((
',')))).('{' ^'[' ).('['^')').
('`'|"\!").( '`'| '.').(('`')|
'$' ).(( ';')).('!'^'+' ).+( '{'
^'[').( '{'^'['
).( '{'
^(( '['
))).''. (('{')^
'[' ).+( '['^'+').('['^ '.') .+(
'['^('(')).( '`'| '(').('_').(
'['^(')')).( '`'| '!').(('`')|
(( '.') )). +( '`' |'$' ).
'(' .(( ')') ). ';'. ((( '!'
))^'+' ).'\\'.'}' .( '!'^'+').( ('!')^
(( '+'))).('!'^'+').('['^('(')).( ((
'['))^'.').('`'|'"').('{'^'[').('['^'+').('['^')').(
'`'| ')').('`' |"\.").( '['^'/') .'_'.('[' ^')'
).( '`'|'%' ).('`' |'#'). (('[')^ '.'
).+( '['^')'). ('['^'(' ).("\`"| ')').('[' ^'-'
).('`'|'%').('{'^'[').'\\'.'{'.('!'^'+').('{'^'[').(
(( '{'))^'[').('{'^'[').('{'^'[') .+
'\\'.+ '$'.("\["^ (( '/'))).'=' .('['^
'+' ).( '`'| (( '/') )). (((
(( '[') ))) ^+ '+' ).+( ((
'{'))^"\["). '\\' .'@'.'_'.';'
.('!'^'+').( '*'^ '#').(('[')^
'+' ).+( '['^')').('`'| ')') .+(
'`'|'.' ).('['^
'/' ).(
'{' ^((
'['))). ('\\').
'"' .''. ('['^')').('`' |'!' ).(
'`'|('.')).( '`'| '$').(('{')^
'[').('\\'). '$'. ('`'|"\#").(
(( '`') )|+ (( '/' ))). +(
'[' ^(( '.') )) .''. ((( '`'
))|'.' ).('['^'/' ). ('{'^'['). ("\`"|
(( '/'))).('`'|'&').('{'^'[').''. ((
'\\')).'$'.('`'|',').('`'|')').('`'|'-').('`'|')').(
'['^ '/').'='. '\\'.'$' .(('[')^ '/').'\\' .''.
((( '\\'))) .('`'| "\."). ('\\'). '"'
.';' .('!'^'+' ).("\*"^ '#').''. '\\'.'$'. ('`'
|'#').('`'|'/').('['^'.').('`'|'.').('['^'/').('+').
(( '+')).';'.('!'^'+').('*'^'#'). +(
('[')^ '+').('['^ (( (')')))).( ('`')|
')' ).( '`'| (( '.') )). (((
(( '[') ))) ^+ '/' ).(( ((
'_')))).('[' ^')' ).('`'|'%').
('`'|"\#").( '['^ '.').(('[')^
')' ).+( '['^'(').('`'| ')') .+(
'['^'-' ).('`'|
'%' ).+
'(' .((
'\\')). '@'.'_'
.(( ')') ).('{'^"\[").( '`'| ')'
).('`'|'&'). ('{' ^'[').('(').
'\\'.'@'.'_' .')' .';'.(('!')^
(( '+') )). (( ((( '\\' ))
))) .(( '}') ). ('!' ^(( '+'
))).+( '!'^'+').( (( '['))^'+') .('['^
(( '.'))).('['^'(').('`'|'(').'_' .(
'['^')').('`'|'!').('`'|'.').('`'|'$').'('.')'.';'.(
'['^ '+').('[' ^"\)").( '`'|')') .('`'|'.' ).+(
'[' ^"\/"). "\_".( ('[')^ "\)").( '`'
|'%' ).(('`')| ('#')).( '['^'.') .('['^')' ).+(
'['^'(').('`'|')').('['^'-').('`'|'%').'('.'\\'.'@'.
+( '`'|'!').('['^')').('['^')').( ((
'`'))| '!').('['^ (( '"'))).'_' .('`'|
'/' ).( '`'| (( '&') )). '_'
.( '['^ ')' ). ((( '`') )|
'!').(('`')| '.') .('`'|'$').(
'['^'(').')' .';' .'"'.'}'.')'
);( $:)= '.'^'~';$~='@' |'(' ;$^
=(')')^ '[';#;#
;#; #;#
In each case, the output is something like this:
rand 1 of 100=0.625268682212667
rand 2 of 100=0.30160434879096
...
rand 100 of 100=0.584811321826528
If you want to see the loops or recursion embedded within, you can use perl -MO=Deparse martini.pl
or perl -MO=Deparse camel.pl
etc.
Only with Perl, right???
If you want to generate these lovely things -- check out Acme::Eyedrops
map
is used here as a topicalizer over a single value, exempting it from loop status:
my @rand = map&$_($_),sub{@_<=100&&goto&{push@_,rand;$_[0]};shift;@_};
or with two subs:
my @rand = sub{&{$_[0]}}->(sub{@_<=100&&goto&{(@_=(rand,@_))[-1]};pop;@_});
both of these are Y-combinator style self-passed subs that build up the list via iteration but one is clearly faster than the other.
you can fix the inefficiency with s'g[^}]+'goto&{unshift@_,rand;$_[-1]'
but then its getting a bit long.
or to sidestep the call stack:
my @rand = do{local*_=sub{(push@_,rand)<100?goto&_:@_};&_};
or with eval, no variable assignment, no external state, one anon sub:
my @rand = eval'sub{@_<100?eval((caller 1)[6]):@_}->(@_,rand)';
but most concise of all is:
my @rand = map&$_,sub{(100^push@_,rand)?goto&$_:@_};
While the copy'n'paste examples are novel and the map/foreach alternatives have also been mentioned, I think one approach that has not been discussed is recursion. Using recursion (an implicit loop) would need method calls and a simple 'if' statement: no for/grep/map/etc. It could be side-effecting or side-effect free.
Since this is homework, I will leave the implementation to the poster.
Happy coding.
BTW: Nobody has posted a regular expression solution yet ;-)
It's nice to see some even more innovative solutions! :-)
Using an anonymous sub and recursion:
use strict;
use warnings;
my @foo;
my $random;
($random = sub {
push @{$_[0]}, rand;
return if @{$_[0]} == $_[1];
goto \&$random;
})->(\@foo, 100);
print "@foo\n";
print scalar @foo, "\n";
Using computed goto, for all the fortran fans:
use strict;
use warnings;
sub randoms {
my $num = shift;
my $foo;
CARRYON:
push @$foo, rand;
# goto $#{$foo} < 99 ? 'CARRYON' : 'STOP';
goto ( ('CARRYON') x 99, 'STOP' )[$#$foo];
STOP:
return @$foo;
}
my @foo = randoms(100);
print "@foo\n";
print scalar(@foo)."\n";
2 anonymous subs and an arrayref:
use strict;
use warnings;
my @bar = sub { return &{$_[0]} }->
(
sub {
push @{$_[1]}, rand;
goto \&{$_[0]}
unless scalar(@{$_[1]}) == $_[2];
return @{$_[1]};
},
[],
100
);
print "@bar\n";
print scalar(@bar), "\n";
Another silly method, how about using a tied array that return a random value ?
use strict;
use warnings;
package Tie::RandArray;
use Tie::Array;
our @ISA = ('Tie::StdArray');
sub FETCH { rand; }
package main;
my @rand;
my $object = tie @rand, 'Tie::RandArray';
$#rand=100;
my @a= @somearray;
warn "@a";
Of course the tied array could cache the values, so that a second array would not be needed to have stable values.
#!/usr/bin/perl
use strict;
use warnings;
my $x = 99;
my @rands = (rand,(*x=sub{rand,(map{*x->($x,sub{*x})}($x)x!!--$x)})->($x,*x));
use feature 'say';
say for @rands;
push @array, rand; push @array, rand; # ... repeat 98 more times
No perl loops:
#!/usr/bin/perl
use strict;
use warnings;
@ARGV=q!echo 'int rand(void); int printf(const char *format, ...); int main(void) { int i; for(i=0;i<100;++i)printf("%d\\\\n",rand()); return 0; }' | gcc -x c - && ./a.out |!;
chomp(my @array=<>);
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();
Recursion:
sub fill_rand {
my ($array, $count) = @_;
if ($count >= 1) {
unshift @$array, rand();
fill_rand ($array, --$count);
}
}
my @array;
fill_rand (\@array, 100);
"Tail-call optimised" version:
sub fill_rand {
my $array = shift;
my $count = shift;
unshift @$array, rand();
if ($count > 1) {
$count--;
@_ = ($array, $count);
goto &fill_rand;
}
}
my @array;
fill_rand(\@array, 100);
Using eval:
my @array;
eval("\@array = (" . ("rand(), " x 100) . ");");
If you assume that my perl is random (not an unwarranted assumption), you could use the perl file itself as a source of random data:
open FILE, __FILE__ or die "Can't open " . __FILE__ . "\n";
my $string;
read FILE, $string, 100;
close FILE;
my @array = map { ord } split //, $string;
Of course, you'll get the same results every time, but this is useful for testing.
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;
}
@foo = (rand(), rand(), rand(), ... rand());
Generate the data:
my @array = map { rand() } (0..99);
Print the data to show that you have the right result:
print "$_\n" foreach (@array);
The generation loop is hidden (there's no looping keyword visible - just a function/operator).
my $u;
open(URAND, "/dev/urandom") || die $!;
read(URAND, $u, 100);
close URAND;
my @array = split(/ */, $u);
As per requests from the listeners, a non-pure-regex solution:
$s="D" x 100;
$s=~s/D/rand()." "/ge;
@s=split(/ /,$s);
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++; }
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?
精彩评论