Sorting hash of hashes


J

Justin C

I have a hash of hashes containing sales orders. The hash is structured
(as below) order number -> line number -> item info. The dump of the
data below is edited for brevity, there are at least half a dozen other
fields at the bottom level of the hash.

I'm trying to sort the orders by order number and then line number so
that I can output them in the order they have been received - how our
customer would expect to see them.

My first sort appears to work OK, but the second level of sorting fails.
I'm missing something simple here, I'm sure, can someone remind me
please?

Justin.


Demo of how it doesn't work as I expect:

#!/usr/bin/perl

use strict;
use warnings;
use YAML;

my $tmp;
while (<DATA>) {
$tmp .= $_;
}
my $all_orders = Load($tmp);

for my $order (sort keys %$all_orders) {
print "Order: ", $order, "\n";
foreach my $line (sort { $all_orders->{$order}{$a} <=> $all_orders->{$order}{$b} } keys %{$all_orders->{$order}}) {
print "Line: ", $line, "\n";
}
}



__DATA__
---
1107/02454:
3859:
stock_code: WP/AAM/VIKINGS
3860:
stock_code: GB/AAM/VIKINGS
3872:
stock_code: WP/BTL/SEAOFSC
4356:
stock_code: GB/IM/FINALFS
1108/02859:
10:
stock_code: WP/KIS/KISSARM
17:
stock_code: AK/AC/LOGORUB
18:
stock_code: ST/AC/OVALLOG
73:
stock_code: WP/PF/BLOCKWA
76:
stock_code: WP/PF/DARKSIO
77:
stock_code: WP/PF/DIVISIE
90:
stock_code: SP/TEST/LOGO
1109/03591:
12:
stock_code: WP/IM/LIVEAFT
13:
stock_code: GB/IM/FEAROFT
14:
stock_code: SB/IM/LOGOFIN
20:
stock_code: SP/MOT/ACEOFSP
22:
stock_code: WP/KIS/CREATUR
24:
stock_code: WP/KIS/FACESPU
25:
stock_code: WP/KIS/KISSARM
38:
stock_code: WP/ACOO/EYESBLA
43:
stock_code: WP/HHOR/TASTETH
52:
stock_code: ST/KIS/CREATUR
57:
stock_code: ST/KIS/DESTROY
60:
stock_code: ST/KIS/DYNASTY
67:
stock_code: SP/KIS/LOGOFAC
69:
stock_code: ST/KIS/LOVEGUN
1109/03609:
415:
stock_code: BA/SFLY/OMEN
16:
stock_code: LA/IM/FINALFR
17:
stock_code: LA/QUE/LOGOAND
19:
stock_code: ST/MOT/BORNTOL
21:
stock_code: ST/MOT/HAMMERE
24:
stock_code: LA/KIS/LOGO
5:
stock_code: BA/FF/LOGOS
55:
stock_code: BA/FF/LOGOS
555:
stock_code: BA/FF/LOGOS
 
Ad

Advertisements

T

Tony Mountifield

I have a hash of hashes containing sales orders. The hash is structured
(as below) order number -> line number -> item info. The dump of the
data below is edited for brevity, there are at least half a dozen other
fields at the bottom level of the hash.

I'm trying to sort the orders by order number and then line number so
that I can output them in the order they have been received - how our
customer would expect to see them.

My first sort appears to work OK, but the second level of sorting fails.
I'm missing something simple here, I'm sure, can someone remind me
please?

Yes, you are sorting on what the second level points at, (HASH(0x12345678)),
rather than the indices themselves. Try this line instead:

foreach my $line (sort { $a <=> $b } keys %{$all_orders->{$order}}) {

Another neat thing you can do is to have this near the top of the program:

sub numerically { $a <=> $b }

and then do this:

foreach my $line (sort numerically keys %{$all_orders->{$order}}) {

Cheers
Tony
 
J

Jim Gibson

Justin C said:
I have a hash of hashes containing sales orders. The hash is structured
(as below) order number -> line number -> item info. The dump of the
data below is edited for brevity, there are at least half a dozen other
fields at the bottom level of the hash.

I'm trying to sort the orders by order number and then line number so
that I can output them in the order they have been received - how our
customer would expect to see them.

My first sort appears to work OK, but the second level of sorting fails.
I'm missing something simple here, I'm sure, can someone remind me
please?

You are sorting on the /value/ of the second-level hash, not the /key/.
See below.
Demo of how it doesn't work as I expect:

#!/usr/bin/perl

use strict;
use warnings;
use YAML;

my $tmp;
while (<DATA>) {
$tmp .= $_;
}
my $all_orders = Load($tmp);

for my $order (sort keys %$all_orders) {
print "Order: ", $order, "\n";
foreach my $line (sort { $all_orders->{$order}{$a} <=>
$all_orders->{$order}{$b} } keys %{$all_orders->{$order}}) {

foreach my $line (
print "Line: ", $line, "\n";
}
}



__DATA__

[data snipped]
 
Ad

Advertisements

J

Justin C

Yes, you are sorting on what the second level points at, (HASH(0x12345678)),
rather than the indices themselves. Try this line instead:

Of course I am! D'oh! Sometimes you just can't see it for looking.

Thank you, and also thanks to Jim, for pointing out the error of my
ways.
foreach my $line (sort { $a <=> $b } keys %{$all_orders->{$order}}) {

Another neat thing you can do is to have this near the top of the program:

sub numerically { $a <=> $b }

and then do this:

foreach my $line (sort numerically keys %{$all_orders->{$order}}) {

I quite like this, it's not anything less to type, but if there's a
whole bunch of sorting to be done it's very clear from the outset what
you're doing.

Justin.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top