You may be making a mistake if there are undefs in your hash. That warning is telling you something. If you don't mind that undef and zero (0) get sorted as the same value, you have nothing to worry about with rata's solution, and the warnings can be ignored. But if undef should be ordered differently from zero, you need to do an additional check.

Please have a look at the following test code that demonstrates three ways to handle your sort, while also dealing with the warnings.

use 5.012_002; use strict; use warnings; my %hash = ( this => 1, that => 4, the => undef, other => undef, those => 2, it => 0, ); # First simply disable the warning temporarily. { no warnings qw/uninitialized/; my @warnsorted = sort { $hash{$a} <=> $hash{$b} } keys %hash; say "Without Warnings:\t@warnsorted"; } # Second, check each item for definedness. my @defsorted = sort { ( defined( $hash{$a} ) && $hash{$a} ) <=> ( defined( $hash{$b} ) && $hash{$b} ) } keys %hash; say "Testing Definedness:\t@defsorted"; # Third, sort with definedness as a criteria my @critsorted = sort { defined( $hash{$a} ) <=> defined( $hash{$b} ) or ( defined( $hash{$a} ) && $hash{$a} ) <=> ( defined( $hash{$b} ) && $hash{$b} ) } keys %hash; say "Defined as Criteria:\t@critsorted";

And the output:

Without Warnings: the it other this those that Testing Definedness: the it other this those that Defined as Criteria: the other it this those that

The first method shown simply disables the warning, lexically scoped to a very narrow scope surrounding the sort. But this doesn't deal with the fact that 'undef' and '0' will get sorted together as the same effective value.

The second method eliminates the warning by not directly sorting undefs. What it does is test each side of the comparison for definedness. If defined, then compare the value on that side of the <=>. If undefined, compare the value returned by defined(), which would be zero in that case. This preserves the possibly errant artifact of undef being comparatively the same as zero.

The third method first does a definedness comparison on both sides of the <=>. If those are equal, then it moves on to a regular sort similar to my second example. This method will promote undef to the top of the heap, above '0'. Of course you could demote it to the bottom of the pile just as easily. But the point is that it sorts undef as a value different from zero.

There's a final solution which reduces the number of calls to defined, by combining the first method with the third:

{ no warnings qw/uninitialized/; my @sorted = sort { defined( $hash{$a} ) <=> defined( $hash{$b} ) or $hash{$a} <=> $hash{$b} } keys %hash; say "Defined as Criteria:\t@sorted"; }

Here we are still sorting with undef as a distinctly different value from zero, but warnings would continue to be generated. Since we're already sure that we've dealt with that warning, it would be safe to just ignore it, which is what the no warnings...... does for us.


Dave


In reply to Re^3: Sorting an array of hashes by a value of hash by davido
in thread Sorting an array of hashes by a value of hash by simonozzy

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.