Beefy Boxes and Bandwidth Generously Provided by pair Networks Russ
Just another Perl shrine
 
PerlMonks  

How do I shuffle an array?

by vroom (His Eminence)
on Jan 08, 2000 at 03:19 UTC ( [id://1869]=perlquestion: print w/replies, xml ) Need Help??

This is an archived low-energy page for bots and other anonmyous visitors. Please sign up if you are a human and want to interact.

vroom has asked for the wisdom of the Perl Monks concerning the following question: (arrays)

How do I shuffle an array?

Originally posted as a Categorized Question.

Replies are listed 'Best First'.
Re: How do I shuffle an array?
by vroom (His Eminence) on Jan 09, 2000 at 05:02 UTC
    The Fisher-Yates shuffle is easy to code up:
    # randomly permutate @array in place sub fisher_yates_shuffle { my $array = shift; my $i = @$array; while ( --$i ) { my $j = int rand( $i+1 ); @$array[$i,$j] = @$array[$j,$i]; } } fisher_yates_shuffle( \@array ); # permutes @array in place
      And mentioned numerous times in numerous places, the 'next if $i == $j' is unnecessary, as it rarely saves an element swap (except on the smallest of arrays), so it actually costs more to do the comparison every time rather than just swapping unconditionally.

      BTW, in case anyone was wondering who these guys Fisher and Yates were, here's some links. They're hard to find when almost every reference to Fisher and Yates (and especially with the term 'shuffle') on Google is a perl reference :-)

RE: How do I shuffle an array?
by chromatic (Archbishop) on Mar 29, 2000 at 17:50 UTC
    In older Perl versions (before 5.004) calling srand was necessary. Now it's called implicitly when rand is first used. See the second paragraph of srand for details. :)
Re: How do I shuffle an array?
by rajib (Novice) on Aug 20, 2002 at 14:13 UTC
    shuffle( \@array ); sub shuffle { my $array = shift; for ( my $i = 0; $i <= $#array; ++$i ) { my $rand = rand($#array); @$array[$i,$rand] = @$array[$rand,$i]; } }

    {Editor's note: This solution is flawed. Read Abigail-II's reply, Re: Answer: How do I shuffle an array?, for an explanation.}

      This "shuffles" the array, but not in a fair way. In fact, the algorithm contains two mistakes, a minor one and a severe one. Let's start with the minor one - in your loop you set $rand to rand $#array. But that means $rand could never be the last element of the array. However, fixing it that you take rand @array will not do you any good.

      Let the size of the array be N. Then at each iteration, you select from N elements (after the fix given above), and change it with the one on position $i. You do this N times. Hence, you will get NN different outcomes. There are however, only N! different permutations of the array. And since N! isn't a divisor of NN for N > 2, some outcomes will be favoured over others by your algorithm.

      Please use the Fisher-Yates shuffle as described in the FAQ. That one is fair.

      Abigail

Re: How do I shuffle an array?
by hossman (Prior) on Jun 15, 2003 at 18:50 UTC
      Independet way:
      my @data = 0..51; my @cards = sort { (-1,1)[rand(2)] } @data ;

      Graciliano M. P.
      "The creativity is the expression of the liberty".

      I prefer japhy's one-liner, which achieves shuffling via fisher-yates:

      @entry[-$i,$j] = @entry[$j,-$i] while $j = rand(@entry - $i), ++$i < @ +entry;
      as an aside - this is in the snippets section. would it not be nice to use snippets, or grinder's fabled categorized snippets library, as a source of data for categorized q&a?

      ttfn,

      ...wufnik

      -- in the world of the mules there are no rules --
      Math::Random::MT::Auto has a shuffle function, as well:
      use Math::Random::MT::Auto 'shuffle'; my @cards = 0..51; shuffle(\@cards);

      Remember: There's always one more bug.
Re: How do I shuffle an array?
by perlplayer (Sexton) on Mar 05, 2008 at 08:28 UTC
    i have solved the issue in my own way i am newbie so if there is any inefficiency in my code please point out...as "there is more than one way to do it"
    my @array=('one','two','three','four','five','six'); &shuffle(\@array); sub shuffle{ my $array=shift; my $max=@$array; #print $max; foreach(@$array) { my $random=int rand($max+1); unless($random eq $max) { @$array[$random,$max]=@$array[$max,$random]; $max--; } } } print "@array\n";
    ** i also have a querry if i omit the $max-- what wrong will happen
      my $random=int rand($max+1); unless($random eq $max)

      The correct way to compare numbers is ==, not eq.

      And when you want to exclude $max from the range of random numbers, write my $random = int rand($max); in the first place.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1869]
help
Sections?
Information?
Find Nodes?
Leftovers?
    Notices?
    hippoepoptai's answer Re: how do I set a cookie and redirect was blessed by hippo!
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.