Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

Re: Sort hash with values

by sundialsvc4 (Abbot)
on Jun 24, 2013 at 12:52 UTC ( #1040426=note: print w/ replies, xml ) Need Help??

in reply to Sort hash with values

I think that I see the problem.   Ordinarily, you would be able to iterate over something like foreach ( sort keys(%IP_store) ) ..., but IP-address strings of varying lengths won’t sort correctly as strings.

The sort verb does allow for a subroutine to be specified, which must return a value that is less than, equal or greater than zero as appropriate, so we do have the mechanism by which to sort the strings the way we want:   as a left-to-right hierarchical collection of four integers.   So, let’s define a separate sub to do this ... something along these (untested) lines:

# 'sort' COMPARISON FUNCTION FOR IP-ADDRESSES. sub ip_compare { # GRAB THE TWO ARGUMENTS PASSED BY 'SORT' my ($a, $b) = @_; # SPLIT THE IP-ADDRESSES INTO FOUR =STRINGS= BY # THE PERIOD CHARACTER. my ($a1, $a2, $a3, $a4) = split('\.', @$a); my ($b1, $b2, $b3, $b4) = split('\.', @$b); # TYPECAST EACH COMPONENT AS INTEGERS, THEN # USE INTEGER '<=>' OPERATOR TO COMPARE NUMBERS. # USE A STACK OF SHORT-CIRCUIT '||' OPS WHICH WILL # STOP AT (AND RETURN) THE FIRST NON-ZERO RESULT # IN THE CHAIN. return (int($a1) <=> int($b1)) || (int($a2) <=> int($b2)) || (int($a3) <=> int($b3)) || (int($a4) <=> int($b4)); }

And I would put that subroutine (when debugged), with its comments, into my program.   There are many ways to write it:   this one is reasonably clear.

Now we can do something like sort (ip_compare, keys(%ip_addr)), or something like that, and it should work.   You iterate over the returned list of keys and retrieve the values from the hash by key.

Comment on Re: Sort hash with values
Download Code
Replies are listed 'Best First'.
Re^2: Sort hash with values
by AnomalousMonk (Canon) on Jun 24, 2013 at 17:53 UTC
    # SPLIT THE IP-ADDRESSES INTO FOUR =STRINGS= BY # THE PERIOD CHARACTER. my ($a1, $a2, $a3, $a4) = split('.', @$a);

    The split built-in function does not use single-quotes around a  /PATTERN/ argument to 'meta-quote' the argument: the  '.' in the above really is trying to split on "any character except newline". Use  '\.' to split on a literal period.

    >perl -wMstrict -le "my $s = ''; ;; my @ra = split '.', $s; print 'naked dot'; printf qq{ '$_'} for @ra; print '@ra elements: ', scalar @ra; ;; @ra = split '\.', $s; print 'escaped dot'; printf qq{ '$_'} for @ra; " naked dot @ra elements: 0 escaped dot 'a' 'bb' 'ccc' 'd'

      Excellent point.   Thank you.   I have updated the post accordingly.   But, even so, my post consisted of extemporaneous coding.   I did not separately test it to see if it would actually run.   I made it only as an illustration of the essential idea, “implementation left as an exercise to the reader.”

        ... extemporaneous coding ... “implementation left as an exercise to the reader.”

        I understand. But given my perception of the relative inexperience of Rahul Gupta WRT Perl coding, and of the relatively subtle nature of the bug and its manifestation, I wanted to be very explicit about the problen I saw.

        I did not separately test it to see if it would actually run.

        My own experience with the excellent advice I customarily dispense is that it always works — except when I don't test it, and then, for some reason, it never works! That's why I always try to provide a "complete input-execution-output experience", usually in the form of some kind of command-line capture. That way, there's no question about execution conditions, code, data, etc... Caveat praeceptor.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1040426]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (9)
As of 2016-05-04 08:19 GMT
Find Nodes?
    Voting Booth?