in reply to Re^3: How would I sort a two-dimensional array by multiple columns?
in thread How would I sort a two-dimensional array by multiple columns?

There are subtle bugsdifferences in interpretation of the OP's request in both jettero and FunkyMonk's solutions.

In essence, neither goes deep enough to resolve differences - jettero stops at the second element, and FunkyMonk stops after index 3.

FunkyMonk - in your code, "@_" inside the sort is probably not what you think it is - at that point, @_ is still the parameter passed into "sortsub". Inside the sort itself, you only have $a and $b. The "@_" comes from the outer sub.

Here is code with slightly modified data, that demonstrates the errors, and my proposed "correct" solution.

#!/usr/bin/perl use strict; use Data::Dumper; use Test::More qw/no_plan/; my $unsorted = [ [ qw/1 3 5 6 2/ ], [ qw/3 4 5 6 7/ ], [ qw/1 2 3 4 5/ ], [ qw/5 6 7 9 9/ ], [ qw/5 6 7 9 8/ ], [ qw/1 2 3 4 5/ ], [ qw/2 2 2 2 2/ ], [ qw/1 1 2 4 5/ ], [ qw/2 3 4 5 6/ ], ]; my $expected = [ [ qw/1 1 2 4 5/ ], [ qw/1 2 3 4 5/ ], [ qw/1 2 3 4 5/ ], [ qw/1 3 5 6 2/ ], [ qw/2 2 2 2 2/ ], [ qw/2 3 4 5 6/ ], [ qw/3 4 5 6 7/ ], [ qw/5 6 7 9 8/ ], [ qw/5 6 7 9 9/ ], ]; my $sorted = FunkyMonkSort($unsorted, 0, 1, 3); is_deeply $sorted, $expected, "FunkyMonk Sort"; # Print ($sorted,"After FunkyMonk Sort"); sub FunkyMonkSort { my @array = @{ +shift }; my @sorted = sort { for my $ix (@_ ) { # Updated from " 0 .. @_" - per updates fr +om FonkyMonk my $cmp = $a->[$ix] <=> $b->[$ix]; return $cmp if $cmp; } return 0; } @array; return \@sorted; } #------------------------------- my @jettero = sort {$a->[0]<=>$b->[0] || $a->[1]<=>$b->[1]} @$unsorted +; is_deeply \@jettero, $expected, "jettero Sort"; #Print ($sorted,"After jettero Sort"); #--------------------- NetWallah ---- my @b =sort NetWallahSort @$unsorted; is_deeply \@b, $expected, "NetWallah Sort"; sub NetWallahSort{ # Auto import $a, $b, which are array refs for my $i(0..$#$a){ next if $a->[$i] == $b->[$i]; return $a->[$i] <=> $b->[$i]; } return 0; #Pathological (Updated from "return 1" per ikegami's nod +e below) } sub Print{ my $aref=shift or die "No array supplied"; my $title=shift || ''; print "----- $title --\n"; for (@$aref){ print "\t" . join(", ",@$_) . "\n"; } print "-------------------\n\n"; }
Output:
not ok 1 - FunkyMonk Sort # Failed test 'FunkyMonk Sort' # at test-arr.pl line 33. # Structures begin differing at: # $got->[7][4] = '9' # $expected->[7][4] = '8' not ok 2 - jettero Sort # Failed test 'jettero Sort' # at test-arr.pl line 49. # Structures begin differing at: # $got->[7][4] = '9' # $expected->[7][4] = '8' ok 3 - NetWallah Sort 1..3 # Looks like you failed 2 tests of 3.
Update: Updated based on ikegami's note below (return 0, not 1);
Also updated FonkyMonk's sort - uses @_ instead of 0..@_.

Update 2: The O.P. has correctly chosen Funkymonk's code as representing what he requested.
My code addresses a different issue - sorting to the complete depth.

     "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

Replies are listed 'Best First'.
Re^5: How would I sort a two-dimensional array by multiple columns?
by TGI (Parson) on Mar 15, 2008 at 23:56 UTC

    While I like your solution, FunkyMonk's routine could be made to sort on all elements of an array by changing its arguments:

    my $sorted = FunkyMonkSort($unsorted, 0..$#$unsorted);

    Your code meets the specification to sort a 2D array where each element in every row is compared.

    FunkyMonk's code solves a different problem--sort a 2D array by an arbitrary subset of elements in each row.

    I spent a while looking for the "bug". There really isn't a bug, it's just that you interpreting the spec differently than FunkyMonk did.

    BTW, I like the way that you called attention the the fact the NetWallaSort() is a sort function, and gets $a and $b automagically.


    TGI says moo

      TGI (++)- Agreed to all your points.

      I had /msg'd FunkyMonk (also ++) that I had misread the OP's requirement.

      I now publicly post that his post was NOT buggy, based on what the OP said he wanted, and his "@_" was indeed what he intended (after his update).

           "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

Re^5: How would I sort a two-dimensional array by multiple columns?
by FunkyMonk (Bishop) on Mar 15, 2008 at 23:32 UTC
    The sort I wrote was written to match the OP's spec: to sort by columns 1, 2 then 4 (which I took to mean 0, 1 and 3 in Perl terms)

    Note that I updated my node a couple of hours before you posted :(

    FunkyMonk - in your code, "@_" inside the sort is probably not what you think it is - at that point, @_ is still the parameter passed into "sortsub". Inside the sort itself, you only have $a and $b. The "@_" comes from the outer sub.
    That's exactly what I intended

    update: much less than a couple of hours:(

Re^5: How would I sort a two-dimensional array by multiple columns?
by ikegami (Patriarch) on Mar 16, 2008 at 03:32 UTC

    I think
    return 1; #Pathological
    should be
    return 0; #Pathological
    $a and $b are equal at that point, so zero should be returned.

    I think some versions of sort in some versions of Perl even crashe when inconsistent results (a < b < a) are returned, something that can happen when returning non-zero for equal values.

Re^5: How would I sort a two-dimensional array by multiple columns?
by dbmathis (Scribe) on Mar 15, 2008 at 22:29 UTC

    NetWallah, That went abit over my head. So how would your code look like?

    I am not clear on how I would implement this to

    input:

    @toBeSorted, 0, 1, 3)

    output:

    @sorted

    Can I see what you code would look like so that I can study the correct way?


    After all this is over, all that will really have mattered is how we treated each other.
      The only relevant part of the code I posted is "sub NetWallahSort".

      Just copy that sub into your code, and use it like:

      my @sorted = sort NetWallahSort @$unsorted; # Or, simply "@unsorted", if @unsorted is an Array-of-Arrays, # rather than a reference.
      FYI - a 2-Dimensional array is technically an "Array of Array-references".

      FonkyMonk makes his declaration ($unsorted) a scalar, which is a "reference to an Array of Array-references", or "a reference to a 2-d Array". As Sienfeld would say - not that there is anything wrong with that!

           "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom