How to generate an array with random values, without using a loop?

后端 未结 24 2095
逝去的感伤
逝去的感伤 2020-12-13 19:23

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

相关标签:
24条回答
  • 2020-12-13 19:52

    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&$_:@_};
    
    0 讨论(0)
  • 2020-12-13 19:53

    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=<>);
    
    0 讨论(0)
  • 2020-12-13 19:54

    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";
    
    0 讨论(0)
  • 2020-12-13 19:54
    #!/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;
    
    0 讨论(0)
  • 2020-12-13 19:54
        push @array, rand;
        push @array, rand;
        # ... repeat 98 more times
    
    0 讨论(0)
  • 2020-12-13 19:55

    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.

    0 讨论(0)
提交回复
热议问题