Monday, August 31, 2009

Some ways that Perl 6 is grand, part 2 of ?

Okay, this is really part 1b of ?, but…

In my earlier post, I used the zip operator to join two lists into a hash.

There was one obvious use of the operator that escaped me at the time, and that was how I sometimes need to create a new hash from the keys of two hashes, or keys and values. And now I think it's starting to look neat:
my %A = { a => 1, b => 2 };
my %B = { z => 9, y => 8 };

my %AB = %A.keys Z %B.keys;
# { "a" => "z", "b" => "y" }

%AB = %A.keys Z %B.values;
# { "a" => 9, "b" => 8 }
However, this is a bit unpredictable, since the hash key order is undefined. So if you expect sorted keys, do that at the same time:
%AB = %A.keys.sort Z %B.keys.sort;
# { "a" => y, "b" => z }

# Sort by B's values - two variants
%AB = %A.keys.sort Z map { %B{$_} }, %B.keys.sort;
%AB = %A.keys.sort Z %B.sort.map( { .value } );
# { "a" => 8, "b" => 9 }
The equivalent Perl 5.10 version would be:
use List::MoreUtils qw/zip/;
my @k = sort(keys(%A));
my @v = map { $B{$_} }, sort(keys(%B));
%AB = zip @k, @v;

I now have a nice-ish argument for upgrading to Perl 5.10.1 on $workplace's servers. :D

masak++ for helping a tired me with the map expression.
Chas. Owens++ for spotting the missing use statement for Perl 5.
Pm++ for another way of sorting by value, just what I was hoping for!
isec++ for spotting a missing sort() for Perl 5.

6 comments:

Chas. Owens said...

I think the 5.10 version is missing

use List::MoreUtils qw/zip/;

bakkushan said...

Thanks, I should've proof-read one more time before posting!

Pm said...

Another approach:

my %AB = %A.keys.sort Z %B.sort.map( { .value } );

bakkushan said...

Heh, with more refinements like these, I'll soon have more attributions than code. :D

Thanks, Pm!

Unknown said...

shouldn't be sorted the %A keys:

my @k = sort(keys(%A));

?

bakkushan said...

Yes, you're absolutely correct, that was a stupid oversight.