Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Sunday January 11, 2009
11:30 AM

No Fisher-Yates Shuffle In Perl 6

[ #38258 ]

When I wrote Hangman in Perl 6, I used the following for shuffling a list:

my method shuffle (*@items) {
    # Fisher-Yates shuffle
    my $i = @items.elems;
    while ($i) {
        my $j = $i.rand.int;
        $i--;
        @items[ $i, $j ] = @items[ $j, $i ];
    }
    return @items;
}

Today I was bothered by this and realized that it's not very Perl 6ish. In fact, Perl 6 is so focused on solving common programmer problems that I realized that the List class should have a shuffle builtin. After much playing around in the internals of Perl 6 and attempting to implement the Fisher-Yates shuffle, I realized that the pick method was better, so I was going to implement it internally with pick, but then I read the documentation more carefully. Shuffling an array in Perl 6 is trivial; the name is just not what I expected.

my @shuffled = @array.pick(*);

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • @array.=pick(*);

    This might even be optimized and actually shuffle the elements within the array.

    • Yeah, I'm discovering that as I'm writing tests for my $string.trim function (and it looks like it will be accepted as part of core Perl 6! Yay! :)

    • Trying that in the hangman code:
      @items.=pick(*);

      gets:
      Null PMC access in find_method()

      if I do either (after:
      my $i = @items.elems;
      ):
      @items.=pick($i);

      or:
      @items = @items.pick($i);

      I get:
      Cannot assign to readonly variable

      Doing:
      return @items.pick($i);

      works though ('*' again gets the Null PMC).

      • That pick seems to work for me:

        ~ $ perl6 -e 'my @items = ^10; @items .= pick(*); @items.perl.say'
        [2, 8, 9, 4, 1, 5, 3, 7, 6, 0]
        ~ $ perl6 -e 'my @items = ^10; my $i = @items.elems; @items .= pick(*); @items.perl.say'
        [6, 2, 7, 1, 4, 8, 9, 5, 3, 0]
        ~ $ perl6 -e 'my @items = ^10; my $i = @items.elems; @items .= pick($i); @items.perl.say'
        [7, 8, 5, 1, 2, 0, 4, 3, 9, 6]
        ~ $ perl6 -v
        This is Rakudo Perl 6, revision 35858 built on parrot 0.9.0-devel
        for darwin-2level.

        Copyright 2006-2008, The Perl Foundation.

        If you up

        • Yeah, I was able to get it to work from the command line yesterday too, so I'm guessing it's got to do w/ @items being a param to a method, maybe?, as in hangman.pl. Just try your new shuffle in there. I was working on making up a smaller test case. I use a nightly fetch of parrot/rakudo.
          • Good news! as of Rakudo Perl 6, revision 35960 built on parrot 0.9.0-devel:
            return @items.pick(*);

            works, at least on x86 Leopard box.