http://www.perlmonks.org?node_id=970921


in reply to Sorting Hash / Array

If each of the quartets was 3 digits long, (010.182.012.000/25, for example), an alphanumeric sort, cmp, would be fine. The Socket module provides a function, inet_aton(), that transforms the quartet into a sortable entity.

I added one more address to test the sort function, (with a key of 36 and value 10.182.2.0/25) Adding this record will show if the sorts are working correctly. It should sort before 10.182.12.0/25 if the sort is correct.

#!/usr/bin/env perl use strict; use warnings; use 5.014; use Socket qw/ inet_aton /; my $data = { '127' => { 'network' => '10.182.48.0/24', 'VLAN' => '3509' }, '32' => { 'network' => '10.182.12.0/25', 'VLAN' => '2121' }, '36' => { 'network' => '10.182.2.0/25', 'VLAN' => '2222' }, '90' => { 'network' => '10.183.243.128/25', 'VLAN' => '3494' } }; my @sorted_keys = map {$_->[0]} sort {$a->[1] cmp $b->[1]} map {[ $_, inet_aton( $data->{$_}{network} =~ /^([.\ +d]+)/) ]} keys %$data; for my $key (@sorted_keys) { printf "%4d%20s%6s\n", $key, $data->{$key}{network}, $data->{$key} +{VLAN}; }

The output is,

C:\Old_Data\perlp>perl 970882.pl 36 10.182.2.0/25 2222 32 10.182.12.0/25 2121 127 10.182.48.0/24 3509 90 10.183.243.128/25 3494 C:\Old_Data\perlp>

If I add the additional line to kcott's code, it gives the following output:

C:\Old_Data\perlp>perl t.pl Key Network VLAN 32 10.182.12.0/25 2121 36 10.182.2.0/25 2222 127 10.182.48.0/24 3509 90 10.183.243.128/25 3494

Hope this helps,

Chris

Update: I see that johngg beat me to the answer and his explanation of why the lexical sort won't sort correctly and why Socket should be used instaed.

Replies are listed 'Best First'.
Re^2: Sorting Hash / Array
by nickt9999 (Acolyte) on May 16, 2012 at 22:27 UTC

    This is why I should have asked the experts at the beginning.

    I really appreciate all your help

    Thanks again

    Cheers

    Nick

Re^2: Sorting Hash / Array
by nickt9999 (Acolyte) on May 17, 2012 at 16:09 UTC

    Hi Chris

    I Have a bit of an issue in that it doesn't seem to sort subnets correctly.

    10.182.8.0/26 10.182.8.0/21 10.182.8.64/26 10.182.8.128/26 10.182.8.192/26
    10.182.32.0/24 10.182.32.0/19 10.182.33.0/24

    I would expect 10.182.8.0/21 to be before 10.182.8.0/26

    Could you help?

    Thanks

    Nick

      Split the network and netmask into separate terms and sort on netmask within network.

      knoppix@Microknoppix:~$ perl -MSocket -Mstrict -wE ' my @networks = qw{ 10.182.8.0/26 10.182.8.0/21 10.182.8.64/26 10.182.8.128/26 10.182.8.192/26 }; say for map { $_->[ 0 ] } sort { $a->[ 1 ] cmp $b->[ 1 ] || $a->[ 2 ] <=> $b->[ 2 ] } map { my( $network, $netmask ) = split m{/}; [ $_, inet_aton( $network ), $netmask ]; } @networks;' 10.182.8.0/21 10.182.8.0/26 10.182.8.64/26 10.182.8.128/26 10.182.8.192/26 knoppix@Microknoppix:~$

      I hope this is helpful.

      Cheers,

      JohnGG