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

for_list and sorting key/value hash pairs

by ibm1620 (Hermit)
on Jan 09, 2023 at 19:21 UTC ( [id://11149464]=perlquestion: print w/replies, xml ) Need Help??

ibm1620 has asked for the wisdom of the Perl Monks concerning the following question:

I am finding the experimental for_list feature in v5.36 very useful - mostly when combined with the indexed builtin or when processing hashes. However, I do frequently want to process hash pairs sequentially by key (similar to for my $k (sort keys %h) { ... }) so I set about looking for a way to do it in a for_list. The best I've come up with is:
#!/usr/bin/env perl use v5.36; no warnings q/experimental::for_list/; use List::AllUtils qw/pairs unpairs/; my %h = map { ( $_, rand ) } ('a' .. 'z'); for my ($k, $v) ( unpairs (sort { $a->key cmp $b->key } pairs %h) ) { say "$k => $v"; }
which is too verbose to be practical. I noticed reading the doc for key/value pair list functions the following:
NOTE: At the time of writing, the following pair* functions that take a block do not modify the value of $_ within the block, and instead operate using the $a and $b globals instead. This has turned out to be a poor design, as it precludes the ability to provide a pairsort function. Better would be to pass pair-like objects as 2-element array references in $_, in a style similar to the return value of the pairs function. At some future version this behaviour may be added. Until then, users are alerted NOT to rely on the value of $_ remaining unmodified between the outside and the inside of the control block.
I don't understand the issue they're raising, but it does sound like a pairsort is what I need. In the meantime, can anyone suggest a better way to sort the pairs when iterating with a for_list over a hash?

Replies are listed 'Best First'.
Re: for_list and sorting key/value hash pairs
by hv (Prior) on Jan 09, 2023 at 19:57 UTC

    My first inclination would be to construct the list in older style:

    for my($k, $v) (map +($_, $h{$_}), sort keys %h) { say "$k => $v"; }

    But note that you can take a key-value hash slice to shorten it, like so:

    for my($k, $v) (%h{sort keys %h}) { say "$k => $v" }

    In a hash slice, if you use @ as the sigil, it will give just the values in the hash; if you use % as the sigil, it gives key-value pairs:

    % perl -E '%h = (1..6); say "arrayish slice"; say for @h{1,5}; say "hashish slice"; say for %h{1,5}' arrayish slice 2 6 hashish slice 1 2 5 6 %
Re: for_list and sorting key/value hash pairs
by tybalt89 (Monsignor) on Jan 09, 2023 at 20:00 UTC
    for my ($k, $v) ( map { $_, $h{$_} } sort keys %h )

    untested :)

Re: for_list and sorting key/value hash pairs
by davido (Cardinal) on Jan 10, 2023 at 14:12 UTC

    for_list is certainly useful, and even for arrays. But in this case it's reasonably clear, and more concise to just use traditional pre-5.36 Perl.

    my %h = map { $_, rand } 'a'..'z'; print "$_ => $h{$_}\n" for sort keys %h;

    Dave

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11149464]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2025-07-14 15:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.