in reply to Re: Choose random element of array?
in thread Choose random element of array?

As mojotoad points out, when you need that "pick once" functionality from the array, splice() works wonders.. (in the example below, the @testarray has 1052 elements, so the counter runs out at 1051:)

use strict; my $counter = 0; my $randstring; my @testarray = ( 'a' .. 'z', 'A' .. 'Z', '0' .. '999' ); do { $randstring .= splice(@testarray, int rand @testarray, 1); ++$counter; } until $counter == 1051; print "$randstring\n";


Replies are listed 'Best First'.
Re^3: Choose random element of array?
by mojotoad (Monsignor) on May 28, 2004 at 19:48 UTC
    Nice snippet. I couldn't help but point out that you already have a built-in counter -- the number of elements in the array. Reworking your example a bit, we get the following:
    use strict; my $randstring; my @testarray = ( 'a' .. 'z', 'A' .. 'Z', '0' .. '999' ); $randstring .= splice(@testarray, rand @testarray, 1) while @testarray; print "$randstring\n";
    Cheers,
    Matt

      That's definitely better -thanks!

Re: Re: Re: Choose random element of array?
by Somni (Friar) on May 28, 2004 at 23:51 UTC

    What you have there is essentially a shuffle and join. Using splice to shuffle is tempting, but inefficient. perlfaq4 already covers this topic well, and List::Util's shuffle makes it convenient.

      Thanks for these pointers, it will take me to the next level of understanding this stuff..

      Now, at what point, do you do the Fisher-Yates thing in your code.. when you've got a larger array to deal with I guess - but how large?

      Tried looking to see if List::Util uses a Fisher-Yates but it seems to be a .so binary, a library.

      You do realize, that now, I will not ever be able to type the word "splice" without severe pangs of guilt and inefficiency...

        Now, at what point, do you do the Fisher-Yates thing in your code.. when you've got a larger array to deal with I guess - but how large?

        I'd suggest always using it. Using List::Util makes it simple, and List::Util is core as of perl 5.8.0. If, for some reason, you can't use List::Util, the algorithm is pretty simple, and is listed there in perlfaq4 for you.

        Tried looking to see if List::Util uses a Fisher-Yates but it seems to be a .so binary, a library.

        There is a C implementation, compiled into the library you mentioned, and a backup Perl implementation. You can read the Perl implementation by opening the file printed with perl -MList::Util -wle 'print $INC{"List/Util.pm"}' in your favorite editor. The C implementation requires viewing the perl source, shuffle is in ext/List/Util/Util.xs. Both are implementations of the Fisher-Yates algorithm.

        As for feeling bad about splice, you should never feel bad about using tools. Generally, you should write your code first so that it is readable, maintainable, and possibly portable, then start worrying about efficiency, preferably after you've done some profiling.