in reply to Need to sort and data structure based on values inside arrayrefs.

G'day shekarkcb,

I got rid of the irrelevent data from the hash. I added more test data to better test the sorting process.

I've assumed that (1) "'NULL'" means a zero-length string; (2) the wanted sort order is undefs first, then zero-length strings, then numerical data in ascending order; (3) the output is an array of arrays for writing to a spreadsheet.

#!/usr/bin/env perl use strict; use warnings; my %data = ( A => [ 0, 1, 2, 3, 99, 5, 6 ], B => [ 0, 1, 2, 3, 9.9999, 5, 6 ], C => [ 0, 1, 2, 3, "", 5, 6 ], D => [ 0, 1, 2, 3, undef, 5, 6 ], E => [ 0, 1, 2, 3, 11, 5, 6 ], F => [ 0, 1, 2, 3, 123.0, 5, 6 ], G => [ 0, 1, 2, 3, '', 5, 6 ], H => [ 0, 1, 2, 3, undef, 5, 6 ], I => [ 0, 1, 2, 3, -11, 5, 6 ], J => [ 0, 1, 2, 3, -1.1, 5, 6 ], ); my @rows = map { [ $_->[0] => @{$data{$_->[0]}} ] } sort { (! defined $a->[1]) ? -1 : (! defined $b->[1]) ? 1 : (! length $a->[1]) ? -1 : (! length $b->[1]) ? 1 : ($a->[1] <=> $b->[1]) } map { [ $_ => $data{$_}[4] ] } keys %data; use Data::Dump; dd \@rows;

Output:

[ ["H", 0 .. 3, undef, 5, 6], ["D", 0 .. 3, undef, 5, 6], ["C", 0 .. 3, "", 5, 6], ["G", 0 .. 3, "", 5, 6], ["I", 0 .. 3, -11, 5, 6], ["J", 0 .. 3, -1.1, 5, 6], ["B", 0 .. 3, 9.9999, 5, 6], ["E", 0 .. 3, 11, 5, 6], ["A", 0 .. 3, 99, 5, 6], ["F", 0 .. 3, 123, 5, 6], ]

-- Ken

Replies are listed 'Best First'.
Re^2: Need to sort and data structure based on values inside arrayrefs.
by Laurent_R (Canon) on Apr 02, 2014 at 19:21 UTC
    Very nice solution. I was also thinking of a succession of ternary operators to handle the undef or "null" special cases, but did not want in my earlier post to decide on those cases without the OP specifying the required behavior for those cases (which is why I suggested an example sorting on another field). Having said that, if the idea is just to sort the (final) sub-arrays (as I understood the OP's requirement), then the two calls to the map function seem unnecessary. We could have just this (using your test data):
    use strict; use warnings; my %data = ( A => [ 0, 1, 2, 3, 99, 5, 6 ], B => [ 0, 1, 2, 3, 9.9999, 5, 6 ], C => [ 0, 1, 2, 3, "", 5, 6 ], D => [ 0, 1, 2, 3, undef, 5, 6 ], E => [ 0, 1, 2, 3, 11, 5, 6 ], F => [ 0, 1, 2, 3, 123.0, 5, 6 ], G => [ 0, 1, 2, 3, '', 5, 6 ], H => [ 0, 1, 2, 3, undef, 5, 6 ], I => [ 0, 1, 2, 3, -11, 5, 6 ], J => [ 0, 1, 2, 3, -1.1, 5, 6 ], ); my @rows = sort { (! defined $a->[4]) ? -1 : (! defined $b->[4]) ? 1 : (! length $a->[4]) ? -1 : (! length $b->[4]) ? 1 : ($a->[4] <=> $b->[4]) } values %data;
    But here again, we don't really know what the OP exactly wants to get.

      What you have there is exactly (or extremely close to) what I originally coded; however, after considering the OP's "writing these values to excel", I quickly changed that to a Schwartzian Transform.

      You're quite correct about not knowing what the OP really wanted. With any of the suggested solutions, questions regarding how an undef is written to a spreadsheet remain outstanding (and this would almost certainly require further coding).

      -- Ken

Re^2: Need to sort and data structure based on values inside arrayrefs.
by shekarkcb (Beadle) on Apr 02, 2014 at 06:37 UTC
    Thank you all for the reply. This is how i achieved the result.

    1). Created another hash with 5th entry as value.
    2). Sorted the that hash, moved keys to an array

    my @sorted = sort { $subHash{$b} <=> $subHash{$a} } keys %subHash;
    , @sorted had the required output.
    Thanks agin for the pointers, closing the thread

    Thanks