uG has asked for the wisdom of the Perl Monks concerning the following question:

use List::Util 'shuffle'; my @numbers = (1..10); my $r1 = pop(shuffle(@numbers)); my $r2 = pop(shuffle(@numbers));
I get a pretty vague error (Unknown error) from the above code, but its from the pop's. I suppose thats because shuffle is returning a list (and therefore cannot be pop'd?). Whats an elegant way to get 2 unique random numbers between 1 and x? It seems like it involves an ugly amount of code to do such a trival task :(

Replies are listed 'Best First'.
Re: Generating 2 unique random integers (So I can't pop a list...)
by BrowserUk (Patriarch) on Sep 11, 2008 at 04:55 UTC

    Close:

    use List::Util 'shuffle'; my @numbers = shuffle(1..10); my $r1 = pop(@numbers); my $r2 = pop(@numbers);
    It seems like it involves an ugly amount of code to do such a trival task

    If you really want it more compact, and never need to go back for more:

    use List::Util 'shuffle'; my( $r1, $r2 ) = (shuffle 1..10)[ 0, 1 ];

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Generating 2 unique random integers (So I can't pop a list...)
by ikegami (Patriarch) on Sep 11, 2008 at 05:00 UTC
    ...which can be simplified to
    use List::Util 'shuffle'; my ($r1, $r2) = shuffle(1..10);

    No need for intermediary storage.

    Update: This was meant to be a reply to BrowserUk, whose node originally ended before the quoted text.

Re: Generating 2 unique random integers (So I can't pop a list...)
by salva (Canon) on Sep 11, 2008 at 06:56 UTC
    you don't need to shuffle the full array, just splice two random elements:
    # my @numbers = (1..10); oops, thanks RMGir! my @a = (1..10); my $r1 = splice @a, rand(@a), 1; my $r2 = splice @a, rand(@a), 1;
    update: splice can be an expensive operation as it has to move all the elements inside the array from the insertion point upwards (complexity O(N)).

    A more efficient approach is:

    sub pop_any (\@) { my $a = shift; my $r = int rand(@$a); @{$a}[$r, 0] = @{$a}[0, $r] if $r; shift @$a } my @a = (1..10); my $r1 = pop_any @a; my $r2 = pop_any @a;
      I think you mean:
      my @numbers = (1..10); my $r1 = splice @numbers, rand(@numbers), 1; my $r2 = splice @numbers, rand(@numbers), 1;
      @a was confusing me...

      Mike
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Generating 2 unique random integers (So I can't pop a list...)
by tilly (Archbishop) on Sep 11, 2008 at 15:34 UTC
    Why create the temporary array?
    my $r1 = 1 + int(rand(10)); my $r2 = 1 + int(rand(10)); $r2 = 1 + int(rand(10)) while $r1 == $r2;
A reply falls below the community's threshold of quality. You may see it by logging in.