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

Say you use the rand command to generate random numbers. I want to create pairs of numbers by randomly picking two numbers from an array of 100 elements. If I pick a number from 1 to 100 for the 1st of the pair, how do I prevent the rand from picking the element again for the 2nd number of the pair? And how do I prevent a repeat interaction?

Replies are listed 'Best First'.
Re: biased random number picking
by toolic (Bishop) on Jul 12, 2012 at 02:49 UTC
    List::Util::shuffle will randomly shuffle a list of numbers, like 1 to 100. Use a slice to grab two of the numbers. These are guaranteed not to be the same.
    use warnings; use strict; use List::Util qw(shuffle); for (1 .. 5) { my @nums = (shuffle(1 .. 100))[0 .. 1]; print "@nums\n"; }
      There is no need to repeat the shuffle each time through the loop. Use the next two numbers.
        That is not the way I interpreted the OP's specification. If the OP had explicitly stated that no pair should contain any repeat number as another pair, then there is no need to have the shuffle in the loop.
        In fact the solution is incorrect unless you do this ... and correct if you do.
Re: biased random number picking
by frozenwithjoy (Priest) on Jul 12, 2012 at 03:40 UTC
    So, essentially you want to sample w/o replacement. If you don't want to make a complete copy of your array (because it is very large or whatever), you can use the random_permuted_index() method from Math::Random. Another benefit to this module is that (as I understand it), the randomization is 'more random' than for rand; however, it may not be an issue in your case. Also, if you want to keep grabbing two at a time over and over, try splice regardless of how you do your sampling. (Splice is like shift/pop on 'roids.) Here is an example:
    #!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use Math::Random; my @array = qw( cat dog shark frog chimp seahorse ); my @permuted_index = random_permuted_index( scalar(@array) ); print "Here is your entire set:\n"; print Dumper @array; print "Here is a random pick of two:\n"; print Dumper @array[ splice( @permuted_index, 0, 2 ) ]; print "And another two (unique from 1st two):\n"; print Dumper @array[ splice( @permuted_index, 0, 2 ) ]; print "And the final two:\n"; print Dumper @array[ splice( @permuted_index, 0, 2 ) ];

    Sample output:

Re: biased random number picking
by Athanasius (Archbishop) on Jul 12, 2012 at 03:24 UTC

    Here is a solution using just an array slice:

    use v5.14; use strict; use warnings; my @options = (1 .. 100); for (1 .. 100) { my $choice = int(rand($#options + 1)); say 'Choice #', $_, ' is ', $options[$choice]; @options = @options[ 0 .. ($choice - 1), ($choice + 1) .. $#option +s ]; }

    HTH,

    Athanasius <°(((><contra mundum

      the slice is expensive and not really required:
      my $choice = int(rand($#options + 1)); say 'Choice #', $_, ' is ', $options[$choice]; $options[$choice] = $options[-1]; pop @options;
Re: biased random number picking
by brx (Pilgrim) on Jul 12, 2012 at 07:32 UTC
    update : not relevant for your question :)
    #my $size = 100; my $first_index = int(rand($size)); my $second_index = (int(rand($size-1)) + 1 + $first_index) % $size;
Re: biased random number picking
by RichardK (Parson) on Jul 12, 2012 at 10:31 UTC

    Or maybe just

    my @values = (100..200); my $i = int( rand(@values) ); my $j = $i; $j = int( rand(@values) ) while $i == $j;

      Since rand takes an expression as its argument and there are 101 elements in @values your code is equivalent to

      my $i = int( rand(101) );

        That's correct :)

        rand returns a value less than the expression so will return an index in the range 0..100. Which is just what we needed -- woot!