http://qs321.pair.com?node_id=257197

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

Hi Monks. I have a quick question. I have the following bit of code:
foreach $orf (sort {$mips{$a} cmp $mips{$b}} keys %mips) { push @mips, $mips{$orf}; }
My problem is several of the $orf values begin with uppercase letters, as opposed to lower case ones. How can I sort these values while ignoring upper/lower case distinctions? Humbly, Evan

Replies are listed 'Best First'.
Re: alphabetize a hash ignoring upper/lower cases
by vladb (Vicar) on May 11, 2003 at 06:12 UTC
    Just compare the lowercase/uppercase variants of the strings. Make sure you convert all of them to common case (using the lc or uc methods). For example, I'd try a code like this:
    foreach $orf (sort {lc($mips{$a}) cmp lc($mips{$b})} keys %mips) { push @mips, $mips{$orf}; }
    (note: didn't test the code snippet, but confident it should work)

    _____________________
    # Under Construction

      For very small hashes, performing two lc(...$a...) calls per sort iteration is okay.

      For larger hashes, performing all those calls per sort iteration will bog you down. As the number of items increases, the number of sorting comparison increases geometrically. If you need speed, look around for the "Schwartzian Transform" (named after our own merlyn).

      my @ordered = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, expensive_function($_) ] } # such as lc() @unordered; # such as keys %hash

      This calls an expensive setup operation once per item and saves the resulting value, then sorts according to these temporary values, then strips away the temporary values, leaving the original items, but in the right order.

      --
      [ e d @ h a l l e y . c c ]

Re: alphabetize a hash ignoring upper/lower cases
by tstock (Curate) on May 11, 2003 at 07:48 UTC
    vladb answer works fine, and I would like to add that if the code you posted is actually what you are doing instead of a simplified example, then you really don't need the keys of the hash and it can all be written as:
    my @mips = sort { lc($a) cmp lc($b) } values %mips;
      if you have a lot of elements doing the case conversion everytime you compare two elements this will be inefficent. i'd suggest:
      my @imps = map { $_->[1] } sort { $a->[0] cmp $b->[0] } map { [ lc $_, $_ ] } values %mips;
Re: alphabetize a hash ignoring upper/lower cases
by bigj (Monk) on May 12, 2003 at 10:27 UTC
    If speed doesn't play that important role, but readability does, I would prefer to use a module:
    use Sort::Naturally; # from CPAN foreach $orf (nsort keys %mips) { push @mips, $mips{$orf}; }
    or perhaps also written as
    my @mips = @mips{nsort keys %mips};

    Greetings,
    Janek

Re: alphabetize a hash ignoring upper/lower cases
by dragonchild (Archbishop) on May 12, 2003 at 13:51 UTC
    Not having anything to do with the original problem, but I'd recommend not using mips as an array and a hash. It can be very confusing for less-experienced maintainers. (Just answered an Anonymonk question with that exact issue.)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.