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

Mapping, Sorting, Mapping on hash-keys

by Tomte (Priest)
on Jul 23, 2002 at 10:09 UTC ( [id://184367]=perlquestion: print w/replies, xml ) Need Help??

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

I found the following snippet of code to sort alphanumeric keys with a default key breaking the alphabetic order
#!/usr/bin/perl # use strict; use Data::Dumper; my $test = { k4 => 1, k2 => 1, k3 => 1, k1 => 1}; my $first = 'k4'; my @list = map { [$_->[0], ($_->[0] eq $first ? '' : $_->[0])] } sort { $a->[1] cmp $b->[1] } map { [$_, ($_ eq $first ? '' : $_)] } keys %$test; print "Erg: " . Dumper(@list);

As I'm fairly new to perl, it took some of my time to see whats going on. And then I thought: Wait! the leftmost map is unnessecary. I tested this with
# # above code repeated # my @list2 = sort { $a->[1] cmp $b->[1] } map { [$_, ($_ eq $first ? '' : $_)] } keys %$test; print "Erg2: " . Dumper(@list2);

and it yielded as expected the same result.

My Question is: Why used the (way more seasoned) perl-hacker this second (the leftmost) map-statement? I'm quite sure I'm missing a crucial point here but can't get it.

Thanks for your time,

Replies are listed 'Best First'.
Re: Mapping, Sorting, Mapping on hash-keys
by mugwumpjism (Hermit) on Jul 23, 2002 at 11:35 UTC

    In the rightmost map,

    map  { [$_, ($_ eq $first ? '' : $_)] } keys %$test;

    The keys in %$test are converted to a list of arrays - [ key, key ], but with the `first' key having null for the second member of the array. (which will sort first with cmp).

    Then, (s)he is then sorting by the second key, which will put the `first' key at the front:

    sort { $a->[1] cmp $b->[1] }

    If you want a string sort to ignore case, you should change this part to something like this:

    sort { ( lc($a->[1]) cmp lc($b->[1]) ) or ( $a->[0] cmp $b->[0] ) }

    So in general we compare the keys converted to lower case. Strictly speaking, this is all you need to do. The second comparison (which will only be tested if the first comparison returns 0, or equal) compares the raw keys directly. This is just to make the code a little more orderly, so you can expect it to return a consistent ordering of, eg `Case' and `case'.

    So, to answer your question - the leftmost map statement is a no-op, however I suspect the coder may have intended to do this:

    my @list = map { $_->[0] } ...

    Then @list would be filled with the actual keys. Then it would be a correct Schwarzian transform.

    Here is a much quicker and more efficient approach to sort a list and keep a key first:

    my @list = sort { ( ($b eq $first) <=> ($a eq $first) ) or ( lc($a) cmp lc($b) ) or ( $a cmp $b ) } keys %$hash;

    This gets rid of the need for all of those temporary anonymous arrays.

Re: Mapping, Sorting, Mapping on hash-keys
by jmcnamara (Monsignor) on Jul 23, 2002 at 11:51 UTC

    You are correct, the leftmost map() is redundant.

    The code seems overly complicated however, the following has the same effect:

    my %tmp = %$test; delete $tmp{$first}; my @list3 = ([$first, ''], map {[$_, $_]} sort keys %tmp);

    Also, the hashref could really just be a plain hash, unless you need to use it elsewhere.


Re: Mapping, Sorting, Mapping on hash-keys
by dimmesdale (Friar) on Jul 23, 2002 at 11:32 UTC
Re: Mapping, Sorting, Mapping on hash-keys
by Anonymous Monk on Jul 23, 2002 at 13:18 UTC
    Thanks for the feedback; to sum it up: I'm not as dumb as I feared to be ;-)

Log In?

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (5)
As of 2024-04-23 21:08 GMT
Find Nodes?
    Voting Booth?

    No recent polls found