Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

How to Shuffle Multidimensional Arrays?

by Withigo (Friar)
on Mar 27, 2003 at 03:37 UTC ( #246158=perlquestion: print w/replies, xml ) Need Help??
Withigo has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,
I am having a problem shuffling each of the sub-arrays within an array-of-arrays. I'm using the Fisher-Yates shuffle algorithm, as found in 'perldoc -q shuffle'; but I can't get it to work. I've tried three approaches, one using an array of strings, another using an array of array references, and the last using a two dimensional array. None of them work, and I'm not sure why; they just print the contents of the array in the original (unshuffled) order. Can anyone give me some tips?
Thanks in advance!

my @weeks = ('@week01','@week02','@week03'); my @weeks_refs = ("\@week01","\@week02","\@week03"); my @weeks_arr = ([0..13],[0..11],[0..11]); my @week01 = (0..13); my @week02 = (0..11); my @week03 = (0..11); for my $ref (@weeks) { for ($i = @$ref; --$i;) { my $r = int rand ($i+1); @$ref[$i, $r] = @$ref[$r, $i]; } } for(@weeks){ print; } for my $ref (@weeks_refs) { for ($i = @$ref; --$i;) { my $r = int rand ($i+1); @$ref[$i, $r] = @$ref[$r, $i]; } } for(@weeks_refs){ print; } for my $ref (@weeks_arr) { for ($i = @$ref; --$i;) { my $r = int rand ($i+1); @$ref[$i, $r] = @$ref[$r, $i]; } } for(@weeks_arr){ print; }

Replies are listed 'Best First'.
Re: How to Shuffle Multidimensional Arrays?
by chromatic (Archbishop) on Mar 27, 2003 at 04:08 UTC

    You're only printing the top level array which is never shuffled. If you were to use Data::Dumper or Data::Denter to print your data structures, you would see that the second-level arrays are indeed shuffled.

    It might be worth making the shuffler into a function:

    sub shuffle { my $array_ref = shift; for ( my $i = @$array_ref; --$i; ) { my $r = int rand ( $i + 1 ); @$array_ref[ $i, $r ] = @$array_ref[ $r, $i ]; } }

    This will let you recurse through an array of arrays:

    sub recursive_shuffle { my $array_ref = shift; for my $element ( @$array_ref ) { recursive_shuffle( $sub_array ) if ref $element eq 'ARRAY'; } shuffle( $sub_array ); }

    (This code is untested.)

Re: How to Shuffle Multidimensional Arrays?
by Enlil (Parson) on Mar 27, 2003 at 04:23 UTC
    First something that works (not that you weren't close, but I had written it before I realized how close you were.):
    use strict; use warnings; my @AoA = ( [0..13], [0..11], [0..11] ); fisher_yates_shuffle(@AoA); foreach ( @AoA ) { print join ",",@$_; print $/; } sub fisher_yates_shuffle { while (my $deck = shift ) { my $i = @$deck; while ($i--) { my $j = int rand ($i+1); @$deck[$i,$j] = @$deck[$j,$i]; } } }
    Reasons things don't work: hope this helps. I think reading over perllol, perlref,perldsc,will help you get a better grasp of what is going on (i did not go that far into detail).


Re: How to Shuffle Multidimensional Arrays?
by BrowserUk (Pope) on Mar 27, 2003 at 05:25 UTC

    Reading your post it struck me that you might have been trying not just to shuffle the elements within the nested arrays, and the order of the nested arrays with the top level, but possibly wanted to shuffle the elements between the arrays?

    I seriously doubt that this is what you wanted to acheive, but it struck me as an interesting intellectual challenge none the less, and so I offer it on that basis:)

    #! perl -slw use strict; use Data::Dumper; sub shuffleRefs (\@) { my $r=pop; $a = $_ + rand @{$r} - $_ and (${$r->[$_]}, ${$r->[$a]}) = (${$r->[$a]}, ${$r->[$_]}) for (0..$#{$r}); } sub shuffle2d { my @refs; push @refs, \( @$_ ) for @_; shuffleRefs @refs; return @refs; } my @data2d = ( [ qw[a b c d e] ], [ qw[1 2 3] ], [ qw[A B C] ], [ qw[I + II III IV] ] ); print "@$_" for @data2d; shuffle2d @data2d; print ''; print "@$_" for @data2d; __END__ C:\test>temp a b c d e 1 2 3 A B C I II III IV 1 a b e II d I c 2 C III A B 3 IV C:\test>

    The interesting thing to note here is that whilst the elements have been shuffled between the nested arrays with proper statistical chance of any given element of any array ending up in any position in its original array or any other, but the size of each of the arrays can be different and the resultant arrays will remain the same size as they started out.

    The trick is to shuffle a flattened array of references to the array elements and swap those elements through the references.

    Now all I have to do is find a use for it:0

    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: How to Shuffle Multidimensional Arrays?
by Withigo (Friar) on Mar 27, 2003 at 03:38 UTC
    Sorry, I forgot to login for my first post to perlmonks! Doh!
Re: How to Shuffle Multidimensional Arrays?
by Withigo (Friar) on Mar 27, 2003 at 18:23 UTC
    Thank you all for the input! I got it to work now.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://246158]
Approved by blaze
Front-paged by astaines
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (6)
As of 2018-03-19 23:02 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (246 votes). Check out past polls.