Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

How would I sort a two-dimensional array by multiple columns?

by dbmathis (Scribe)
on Mar 15, 2008 at 19:48 UTC ( #674374=perlquestion: print w/ replies, xml ) Need Help??
dbmathis has asked for the wisdom of the Perl Monks concerning the following question:

Hi All,

I wasn't sure if there is an easy way to do what I am trying to do and I was not able to find anything on google.

When I use excel I am able to sort by one column and then by another column and so on, but with perl instead, of course...

For example I have a two-dimensional array '@test' that looks like the following.

1  3  5  6  2
3  4  5  6  7
1  2  3  4  5
5  6  7  8  8
1  2  3  4  5
2  2  2  2  2
1  1  2  4  5
2  3  4  5  6

I would like to make a sub that would allow me to pass in the array and the columns that I want to sort and the the sub output the sorted array by to @test.

Basically pass @test into the sub and sort by column 1 then 2 then 4.

&sortSub(@test, 1, 2, 4); after the sort

1  1  2  4  5
1  2  3  4  5
1  2  3  4  5
1  3  5  6  2
2  2  2  2  2
2  3  4  5  6
3  4  5  6  7
5  6  7  8  8

Does anyone know of an easy way to do this? Does anyone happen to have a routine that already does this?


After all this is over, all that will really have mattered is how we treated each other.

Comment on How would I sort a two-dimensional array by multiple columns?
Re: How would I sort a two-dimensional array by multiple columns?
by jettero (Monsignor) on Mar 15, 2008 at 19:55 UTC

    It would look something like this:

    my @a = ([1,2], [3,4]); my @b = sort { $a->[0] <=> $b->[0] || # the result is -1,0,1 ... $a->[1] <=> $b->[1] # so [1] when [0] is same } @a;

    Check out sort for the full story. And, you'd probably have to maintain some kind of global setting for the sub (indicating which columns to sort by) or call the sub from the sort block indicating it there. Although, calling functions from the sort block can get surprisingly slow. The worst case is O(n*log(n)) I believe and calling functions in perl is among the slowest thing it does.

    I'm sure you'll figure it out.

    UPDATE: NetWallah, sorry, no bugs here. This was not intended to be a complete solution. What's the fun in having someone else write it all out for you?

    -Paul

      Worked like a CHARM! Thanks! That was also MUCH easier than I would have ever imagined. Best Regards

      After all this is over, all that will really have mattered is how we treated each other.
Re: How would I sort a two-dimensional array by multiple columns?
by skirnir (Monk) on Mar 15, 2008 at 20:22 UTC
    You'll get your desired result by sorting by the columns in reverse order of priority, that means, in your example, by ordering the array by the 4th column, then the 2nd, then the 1st.
    It's likely not the fastest possible solution, but it yields the desired result.
Re: How would I sort a two-dimensional array by multiple columns?
by FunkyMonk (Canon) on Mar 15, 2008 at 20:35 UTC
    And if you really want a subroutine...
    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 8 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 8 8/ ], ]; my $sorted = sortSub($unsorted, 0, 1, 3); is_deeply $sorted, $expected; sub sortSub { my @array = @{ +shift }; my @sorted = sort { for my $ix ( @_ ) { my $cmp = $a->[$ix] <=> $b->[$ix]; return $cmp if $cmp; } return 0; } @array; return \@sorted; }

    Update: Fixed a mistake spotted by dbmathis Narveson.

        Yes, you're right. I'll update the node now.

        Thanks

      How would I make this work if I am passing in @unsorted rather than $unsorted?

      After all this is over, all that will really have mattered is how we treated each other.
        I had already indicated that in the comment of my previous node. Here it is again:
        my @sorted = sort NetWallahSort @unsorted;
        Note : I have updated "sub NetWallahSort" in the posted code, to include ikegami's suggestion, returning "0" instead of "1" when sort elements are equal. Please use a current copy of that code.

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

      Hi Funk, I like your solution and I am able to get it working fine in test, however in my existing code I will be passing a list of array references within an array to the routine (@unsorted).

      For example here's the part of my code where I am loading the array:

      while ( @row = $sth->fetchrow_array ) { push @x, [ @row ]; }
      $rindex = 0; $i = 1; do { foreach ( @columns ) { if ( $_ <= $qstart_column - 2 ) { $unsorted[$rindex][$_] = $x[$i][$_]; } else { $unsorted[$rindex][$_] = $x[$i][$_ - $nun_of_questions +]; } } $rindex += 1; $i += $nun_of_questions; } while ( $i <= $#x );

      Right now when run your code in my code I get the following:

      Use of reference "ARRAY(0x10b5810)" as array index at /home/dmathis/qw +est_qqs/transpose-qqs-dev line 367. Use of reference "ARRAY(0x10b5810)" as array index at /home/dmathis/qw +est_qqs/transpose-qqs-dev line 367. Use of uninitialized value in numeric comparison (<=>) at /home/dmathi +s/qwest_qqs/transpose-qqs-dev line 367. Use of uninitialized value in numeric comparison (<=>) at /home/dmathi +s/qwest_qqs/transpose-qqs-dev line 367. ................ ................ ................

      I just need to figure out what to alter in your code to handle my array.

      Best Regards

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://674374]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (15)
As of 2014-08-20 09:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (108 votes), past polls