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

Dear Monks, I have a data structure like this:

$VAR1 = { '1.2.3.4' => { '27029' => 5, '20617' => 1 + }, + '1.2.3.5' => { + '51509' => 1, + '17427' => 1, + '63961' => 7, + '22331' => 1, + '20780' => 7 + }, + '1.2.3.6' => { + '1500' => 3 + }, + };
It's a HoH where nested keys are ports and values are number of connections to that port. I'm printing out the data like this:
for my $ip ( keys %conn ) { for my $port ( keys $conn{$ip} ) { if ( $conn{$ip}{$port} > $max_conns ) { printf "%-15s connected to TCP port %5d %9d times\n", $ip, + $port, $conn{$ip}{$port}; } } }
I'd like to sort the output based on the number of connections to a port, ex.:
1.2.3.5 connected to TCP port 20780 7 times 1.2.3.4 connected to TCP port 27029 5 times 1.2.3.6 connected to TCP port 1500 3 times ...
How do I write a sort like this? (You can find the whole script here.)

Well done is better than well said. -- Benjamin Franklin

Replies are listed 'Best First'.
Re: Sorting a HoH by values of the nested hashes
by hdb (Monsignor) on Nov 20, 2013 at 12:42 UTC

    I cannot see any other way than to first flatten the structure (like Anonymonk before me) and then to sort and print:

    printf "%-15s connected to TCP port %5d %9d times\n", @$_ for sort { $b->[2] <=> $a->[2] } grep { $_->[2] > $max_conns } map { my $ip = $_; map { [ $ip, $_, $conn{$ip}{$_} ] } keys %{$con +n{$ip}} } keys %conn;

    Update: Added the grep-line to incorporate the check as in OP.

Re: Sorting a HoH by values of the nested hashes
by Anonymous Monk on Nov 20, 2013 at 12:34 UTC
Re: Sorting a HoH by values of the nested hashes
by Laurent_R (Canon) on Nov 20, 2013 at 13:29 UTC

    Hi

    There must be a better way, but this the best idea I could come up quickly from the top of my mind, and it works:

    use strict; use warnings; my @array; my $VAR1 = { '1.2.3.4' => { '27029' => 5, '20617' => 1 }, '1.2.3.5' => { '51509' => 1, '17427' => 1, '63961' => 7, '22331' => 1, '20780' => 7 }, '1.2.3.6' => { '1500' => 3 }, + }; for my $var1 (keys %$VAR1) { push @array, [$var1, $_, $$VAR1{$var1}{$_}] for keys %{$$VAR1{$var +1}}; } print map {$_->[0], "\t", $_->[1], "\t", $_->[2], "times \n"} sort {$a +->[2] <=> $b->[2]} @array;
    Output:
    1.2.3.5 51509 1times 1.2.3.5 17427 1times 1.2.3.5 22331 1times 1.2.3.4 20617 1times 1.2.3.6 1500 3times 1.2.3.4 27029 5times 1.2.3.5 63961 7times 1.2.3.5 20780 7times

    Update This is strange, there was no answer when I posted my answer, and now it appears that two monks actually posted before me. I do not understand this and would probably have not posted the above if I has seen the prevoous answers.

Re: Sorting a HoH by values of the nested hashes
by Random_Walk (Prior) on Nov 20, 2013 at 23:06 UTC

    Fun with maps

    use strict; use warnings; use 5.010; use Data::Dumper; # ip => port => count my $d = { '1.2.3.4' => { '427029' => 41, '420617' => 42, }, '1.2.3.5' => { '551509' => 51, '517427' => 52, }, '1.2.3.6' => { '671500' => 61, '622331' => 62, }, }; my $ip; say for sort map { $ip = $_;map { sprintf "%04d connections %s -> %s", $d->{$ip}->{$_}, $ip, $_ } keys %{$d->{$ip}} } keys %$d;

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!