Richard Hainsworth
Richard Hainsworth

Reputation: 2125

How do use a sort on a hash in a for

I have a hash %h and I want to process the data in a for statement in alphabetical order of keys.

But if I use a sort on the hash I get a list of Pairs, which is understandable. But how do I unpack this for a for statement.

Currently I'm using the following:

my %h = <xabsu ieunef runf awww bbv> Z=> 1..*; # create a hash with random key names
for %h.sort { 
  my ($name, $num) = (.key, .value);
  say "name: $name, num: $num"
}
# Output
# name: awww, num: 4
# name: bbv, num: 5
# name: ieunef, num: 2
# name: runf, num: 3
# name: xabsu, num: 1

But I would prefer something like the more idiomatic form:

my %h = <xabsu ieunef runf awww bbv> Z=> 1..*; # create a hash with random key names
for %h.sort -> $name, $num {   
  say "name: $name, num: $num"
}
# Output
# name: awww       4, num: bbv       5
# name: ieunef     2, num: runf      3
# Too few positionals passed; expected 2 arguments but got 1
#   in block <unit> at <unknown file> line 1

I'm sure there is a neater way to 'unpack' the Pair into a signature for the for statement.

Upvotes: 9

Views: 147

Answers (2)

Richard Hainsworth
Richard Hainsworth

Reputation: 2125

Raising @Joshua 's comment to an answer, a neater way is:

%h.sort.map(|*.kv) -> $name,$num { ... }

This uses two Raku features:

  • * inside the map is the Whatever star to create a closure
  • | flattens the resultant list, so that after -> the $name, $num variables do not need to be inside parens.

Upvotes: 2

Elizabeth Mattijsen
Elizabeth Mattijsen

Reputation: 26924

The neater way:

for %h.sort -> (:key($name), :value($num)) {

This destructures the Pair by calling .key and .value on it, and then binding them to $name and $num respectively.

Perhaps a shorter, more understandable version:

for %h.sort -> (:$key, :$value) {

which would create variables with the same names the methods got called with.

Upvotes: 11

Related Questions