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

I have a HoA data
my %HoA={ 1=>["ab",20090101,91010], 2=>["cd",20090101,91010], 3=>["ef",20090201,101000], ...... }
array's columns are name,date and time; I want sort this HoA first by date*1000000+time and second by key. I remmber that we can use
sort {$a->{'date'} <=> $b->{'date'} || $a->{'dataentry'} <=> $b->{'dat +aentry'}} @AoH;
to sort AoH, but I am not sure
sort { ($HoA{$a}[1]*1000000+$HoA{$a}[2]) <=> ($HoA{$b}[1]*1000000+$HoA +{$b}[2]) || $a <=> $b} keys(%HoA)
is that ok? -----yes I tried it, but it can not run

Replies are listed 'Best First'.
Re: sort HoA by tow keys
by shmem (Chancellor) on Mar 23, 2009 at 12:48 UTC
    I have a HoA data

    You don't.

    You have a hash %HoA with one key (a stringified hash reference) and no value. Had you used warnings, perl had told you:

    Reference found where even-sized list expected at ...

    You surely mean:

    my %HoA= ( 1=>["ab",20090101,91010], 2=>["cd",20090101,91010], 3=>["ef",20090201,101000], ...... );

    That corrected, your sorting should work.

Re: sort HoA by tow keys
by moritz (Cardinal) on Mar 23, 2009 at 10:29 UTC
    is that ok?

    Why don't you just try it? Then you know if it's OK.

Re: sort HoA by tow keys
by AnomalousMonk (Archbishop) on Mar 23, 2009 at 21:54 UTC
    The previous replies address and correct a problem with the data format in the OP. This reply addresses a question of style.

    Since the intent seems to be to do a multi-key sort (first by date, then by time and then by hash key), this intent is more clearly and maintainably implemented by sorting in just this way.

    Although the main benefit is clarity, there may also be a side-benefit of better performance, since the relatively expensive (as well as messy) arithmetic operations are not needed for each comparison of the sort.

    If performance is really an issue due to hash size, a ST or GRT approach may be merited. See A Fresh Look at Efficient Perl Sorting and also Old sorting paper holds the key to unlocking the secrets of the Schwartzian Transform for a discussion of and general comments on both approaches.

    Sort by combined date-time, then key:

    >perl -wMstrict -le "my %HoA = ( 2 => ['cd', 20090101, 91010], 3 => ['ef', 20090201, 101000], 1 => ['ab', 20090101, 91010], ); my @ordered_keys = sort { ($HoA{$a}[1]*1000000+$HoA{$a}[2]) <=> ($HoA{$b}[1]*1000000+$HoA{$ +b}[2]) || $a <=> $b } keys (%HoA); for my $key (@ordered_keys) { print qq{$key -> [@{$HoA{$key}}]} } " 1 -> [ab 20090101 91010] 2 -> [cd 20090101 91010] 3 -> [ef 20090201 101000]
    Sort explicitly by date, time, key:
    >perl -wMstrict -le "my %HoA = ( 2 => ['cd', 20090101, 91010], 3 => ['ef', 20090201, 101000], 1 => ['ab', 20090101, 91010], ); my @ordered_keys = sort { $HoA{$a}[1] <=> $HoA{$b}[1] || $HoA{$a}[2] <=> $HoA{$b}[2] || $a <=> $b } keys %HoA; for my $key (@ordered_keys) { print qq{$key -> [@{$HoA{$key}}]} } " 1 -> [ab 20090101 91010] 2 -> [cd 20090101 91010] 3 -> [ef 20090201 101000]
Re: sort HoA by tow keys
by Anonymous Monk on Mar 23, 2009 at 13:06 UTC
    Well, the first thing wrong is you're initializing your hash with a HASHREF, not a hash. You might want to define the hash like this:
    my %HoA=( 1=>["ab",20090101,91010], 2=>["cd",20090101,91010], 3=>["ef",20090201,101000], ...... );
    Remember, hashes are initialized as lists; you could just as easily say
    my %HoA = ( 1, [...], 2, [...], 3, [...], ... );
    The initialization in your example, however, is effectively the following:
    my %HoA = ( {...}, undef );
    Your hash has one key--a reference to the data structure you built--and no values.

    With that one change, the code runs, and that appears to be the meat of your question.