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

I'm not really getting how it's in the FAQ. Basically, given:

my @array = (1,2,3,'a','b','c');

I want that shuffled up to give something like 3,a,1,c,2,b or whatever. I have been looking around google and the FAQ here, but the one same example keeps poping up, which I don't fully follow. Anyway, if anyone could explain this to me, I would appreciate it =)

Replies are listed 'Best First'.
Re: Shuffle an array
by jdporter (Paladin) on Nov 09, 2002 at 02:10 UTC
    If you search for "shuffle" on CPAN, you'll find Shuffle.pm by Abigail, which implements the Fisher-Yates algorithm everyone keeps mentioning. If you want to see how it really works, take a look at the code in that module.

    The basic idea is, looking at each slot in the array, from the last to the first, swap it with one other before it in the array, chosen at random. That is, if you have an array of length 6, swap $a[5] (the last element) with one chosen at random from @a[0..4], then swap $a[4] with one from @a[0..3], and so on down. Obviously, when you get to $a[1], you can stop.

    This is a very effective shuffling technique (assuming you've got a good random number generator). For a good explanation of why, you can read the documentation for Abigail's module.

    jdporter
    ...porque es dificil estar guapo y blanco.

Re: Shuffle an array
by BrowserUk (Patriarch) on Nov 09, 2002 at 01:25 UTC

    Basically the method works like this.

    N is the number of items in the array.

    Pick an element from 1 to N at random. Switch that element with the first element.

    Now pick an element between 2 and N at random. Switch that element with the second element.

    Then pick an element beween 3 and N at random. And switch that element with the third element.

    Repeat those two step N-1 times and you have shuffled the array.

    If that doesn't explain it for you, try getting a pack of card, put them in order and do the process manually.Even using cards 1 to 6 and a dice, and doing the process a couple of times should clarify things if my words don't help.

    In Perl, the counting runs 0 to N-1 each time, but the logic remains the same.


    Nah! You're thinking of Simon Templar, originally played (on UKTV) by Roger Moore and later by Ian Ogilvy
      Ah, ok. Make more sense now (yea, I got the N-1 stuff ;)). Didn't exactally know how the whole process worked. Thanks =)
      Hi BrowserUk,

      This doesn't give a fair shuffle. This is well documented, as it is in the FAQ, and is explained well in the Perl Cookbook. A recent node explains it. Check here.

      cheers

      thinker

        Are you saying my description is inaccurate? If so, please clarify in what way you think that it is wrong.

        My description is accurate. The link you give chooses a random value from 1 to n each time. My description reduces the range by 1 each time. This is the correct Fisher-Yates technique.


        Nah! You're thinking of Simon Templar, originally played (on UKTV) by Roger Moore and later by Ian Ogilvy
Re: Shuffle an array
by DamnDirtyApe (Curate) on Nov 09, 2002 at 20:26 UTC

    I'm suprised no one has mentioned it yet, but List::Util has a shuffle() method that does just that.

    use List::Util qw( shuffle ) ; my @arr = qw( a b c d e f A B C D E F ) ; print( ( map { "[$_]" } @arr ), "\n" ) ; for ( 1..5 ) { print( ( map { "[$_]" } shuffle @arr ), "\n" ) ; }

    _______________
    DamnDirtyApe
    Those who know that they are profound strive for clarity. Those who
    would like to seem profound to the crowd strive for obscurity.
                --Friedrich Nietzsche