'$value'"; } ...">

Sorting a hash pair

my %hash =
    two   => 2,
    three => 3,
    one   => 1,
;

for %hash.sort(*.key)>>.kv -> ($key, $value) {
    say "'$key' => '$value'";
}

      

Is the %hash.sort({.key})>>.kv

above equivalent sorting?

Why doesn't this view work without a hyper >>

prompt?

+3


source to share


2 answers


sort

returns a List of Pairs .

Since calling .kv

on a list returns a list of index, Pair

lists you don't want; you cannot just call .kv

. So you have to pull the key and value from the Pair objects separately by calling a method .kv

on each one that >>.kv

does.

You could use instead .map(*.kv)

.

The syntax >>.kv

allows an implementation to propagate work across multiple threads, if it makes sense to do so.
(Currently, Rakudo just does the job in a semi-random manner so people can't misuse this feature)


There is an alternative way to write a loop by extracting attributes using adverbs in the signature:

for %hash.sort -> (:$key, :$value) {
  say "'$key' => '$value'";
}

for %hash.sort -> $pair (:$key, :$value) {
  say $pair;
  say $key === $pair.key and $value === $pair.value; # True␤
}

# :$key is short for :key($key)
for %hash.sort -> (:key($k), :value($v)) {
  say "'$k' => '$v'";
}

      

This can be useful for other objects that do not have a method to list their public attributes.

class C { has $.a; has $.b; has $.c; has $!private-value }
my $c = 5;
my $obj = C.new(:a<A>,:b(1),:$c);

given $obj -> ( :$a, :b($b), :$c) ) {
  say "$a $b $c";
}

# ignore $.a by using an unnamed scalar
given $obj -> ( :a($), :$b, :$c ) { ... }

# places any unspecified public attributes in %others
given $obj -> ( :$a, :$b, *%others ) {
  .say for keys %others; # c␤
}

# ignores any unspecified attributes
# useful to allow subclasses to add more attributes
# or to just drop any values you don't care about
given $obj -> ( :$a, :$b, *% ) { ... }

# fails because it doesn't handle the public c attribute
# in the sub-signature
given $obj -> ( :$a, :$b ) { ... }

      

This is just the beginning of what is possible with signatures.



The following example also allows subroutines and method signatures, which are optional and completely overloaded for this example. This is really useful in multisite and multiple methods to limit possible candidates.

for 'one' => 1, 1/3
->
  # Type is an alias to the object type
  ::Type Any $_ # Any is the default type requirement

  # the public attributes of the object
  (
    ::A-Type Any :key(   :numerator(   $a ) ),
    ::B-Type Any :value( :denominator( $b ) ) where $b >= 1,
  )
{
  my Type $obj = $_; # new variable declared as having the same type
  my A-Type $new-a = $a;
  my B-Type $new-b = $b;

  # could have used $_.^name or .^name instead of Type.^name
  # so you don't actually have to add the alias to the signature
  # to get the name of the arguments type
  say Type.^name, ' ', $_;
  say '  ', A-Type.^name, ' ', $a;
  say '  ', B-Type.^name, ' ', $b;
}

      

Pair one => 1
  Str one
  Int 1
Rat 0.333333
  Int 1
  Int 3

      


As far as usage goes .sort({.key})

, yes, it's basically the same thing sort

that anything Callable accepts .

I would like to point out that you don't even need to give an argument sort

, because it's even smarter by default than what you gave it.

Perl 6 has many ways to create and access Callable . So any of the following would have worked:

*.key
{ .key } # { $_.key }
-> $_ { .key } # basically what the previous line turns into
{ $^placeholder-var.key }
sub ($_) { .key }
&a-subroutine-reference # you would have to create the subroutine though

      

Also, since all normal operators are actually subroutines, you can use them elsewhere where you need Callable . (I can't think of what works in this place though)

&infix:<+> # the subroutines responsible for the numeric addition operator
&[+] # ditto

&prefix:<++>
&postfix:<++>

# etc

      

+6


source


As far as I can tell, the single difference between the two versions is to use an implicit parameter block $_

instead of using Whatever-Star, so they are indeed equivalent.

This is Perl, so there is more than one way to do it:

*.key
{ .key }
{ $^arg.key }
-> $arg { $arg.key }

      

Why doesn't this view work without a hyper >>

prompt?

sort

forces the hash to a list of pairs and what you get:

say %hash.sort(*.key).perl;
# ("one" => "1", "three" => "3", "two" => "2")

      

To get rid of the pairs, you need to iterate over the list and call .kv

for each of them:

say %hash.sort(*.key)>>.kv.perl;
# (("one", "1"), ("three", "3"), ("two", "2"))

say %hash.sort(*.key).map(*.kv).perl;
# (("one", "1"), ("three", "3"), ("two", "2"))

      



You can force Hash

before calling .kv

:

say %hash.sort(*.key).hash.kv.perl;
# ("one", "1", "three", "3", "two", "2")

      

but this will of course defeat the purpose of the exercise, since you cannot rely on hash order.

You may have noticed that you will get different results depending on how you write the code. If there is no trailing .list

, then you are actually getting Parcel

, not List

, but the semantics have not been finalized.

Note that while the returned objects are all perlified with simple parentheses, some are parcels and some are lists, which you can check by calling .WHAT

. This is still going on.

Also note the inner brackets in some of these options, which you can get rid of the call .flat

. If you do, you can use -> $key, $value

as a signature for your for loop instead of -> ($key, $value)

(or more explicitly -> $anon ($key, $value)

) that uses signature binding to unpack parcels.

Instead of using, .kv

you can use the same approach to unpack paired objects:

for %hash.sort(*.key) -> (:$key, :$value) {
    say "'$key' => '$value'";
}

      

+4


source







All Articles