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

Hi everyone

Got a tricky one .. that I'm havin trouble with wrappin' my head around. :-)

I got a hash:

$Records{'CustomerID'}{'Meta'}{'Name'} $Records{'CustomerID'}{'Packages'}{'PackageID'} ... and some more irrelevant stuff. :-)

I would like to sort the hash alphabetically on {'CustomerID'}{'Meta'}{'Name'} and thus returning the correct 'CustomerID's. I did start out here:

foreach $Customer (sort { $Records->{$a}{'Meta'}{'Name'} cmp $Records->{$b}{'Meta'}{'Name'} } keys %Records) {

.. but .. ahem .. gaah .. does not compute. A hint on how to reach the correct syntax for my sorting, would be much apretiated. :-)

Replies are listed 'Best First'.
Re: Sorting hash on deep value
by hippo (Archbishop) on Nov 04, 2019 at 11:40 UTC
    does not compute

    I'm afraid that this just doesn't suffice as a description of the problem. You would not accept this from one of your users so please take a moment to understand why it does you no favours here.

    Here is the SSCCE illustrating that LanX is probably right.

    #!/usr/bin/env perl use strict; use warnings; use Test::More tests => 1; my %records = ( 123 => { Meta => { Name => 'Bob' } }, 124 => { Meta => { Name => 'Alice' } }, 125 => { Meta => { Name => 'Eve' } } ); my @sortedkeys = sort { $records{$a}{Meta}{Name} cmp $records{$b}{Meta +}{Name} } keys %records; is_deeply \@sortedkeys, [124, 123, 125], 'Sorted by name';
Re: Sorting hash on deep value
by tobyink (Canon) on Nov 04, 2019 at 11:26 UTC

    Do you mean something like:

    $Records{'1'}{'Meta'}{'Name'} = 'Alice'; $Records{'1'}{'Packages'}{'PackageID'} = 1; $Records{'2'}{'Meta'}{'Name'} = 'Bob'; $Records{'2'}{'Packages'}{'PackageID'} = 1;

    If so, you can get a list of customer ids sorted by name like this:

    my @sorted = map $_->[0], # transform pairs back into + ids sort { $a->[1] cmp $b->[1] } # sort by name map [ $_, $Records{$_}{Meta}{Name} ], # transform into [id, name] + pairs keys %Records; # list of customer ids

    If that's not your data structure, could you please post a small example of your data?

      I had to sort a hash on a deep value and was drawing a blank when I came across this node. Your technique works well (and I understand it so no cargo =) Thank you tobyink!
Re: Sorting hash on deep value
by LanX (Saint) on Nov 04, 2019 at 11:20 UTC
    > does not compute

    I.e. does not compile?

    Hash %Records or hash-ref $Records ?

    Please compare

     $Records{'CustomerID'}

    vs

    $Records->{$a}

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Sorting hash on deep value
by BillKSmith (Monsignor) on Nov 04, 2019 at 16:58 UTC
    Several monks have already told you that your only error is trying to use the symbol $Records as both a hash and a hash reference. This is an easy mistake to make it is one of the reasons why we tell everyone to ALWAYS use 'use strict'. Perl would tell you that one of them is a Global Symbol and requires an explicit package name. When you are given the offending line number and variable name, you should be able to figure it out yourself.
    Bill
Re: Sorting hash on deep value
by Fletch (Bishop) on Nov 04, 2019 at 14:24 UTC

    Perl hashes are by definition unordered so you can't sort them*. As you've been given answers you can get a sorted list of the keys based on deep values, but you're not doing anything to the hash itself.

    </nitpick mode="pedantic">

    (*) Unless you're monkeying with tie (e.g. Tie::Hash::Sorted), in which case you're strictly speaking not dealing with plain perl hashes any more.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Sorting hash on deep value
by Anonymous Monk on Nov 07, 2019 at 01:27 UTC
    At this point I would suggest that you take a step back and consider whether a hash or an array (or, maybe an array of hashes?) might be the best fundamental representation in your program. Because, what you are basically trying to do in this single statement ... what you are probably asking Perl to do ... is to construct and then sort an array on-the-fly. (This will be true if-and-when you get this statement working ...) Well, that's a very expensive thing to do, especially when you don't realize that you're doing it.
      Well, that's a very expensive thing to do

      I'd suggest a Benchmark instead of just saying something like that.