http://www.perlmonks.org?node_id=64430

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

Given a multi dimensional, what is the best way to sort the array numerically? eg:
@array = ( [5,7,2],[9,4,8],[1,6,3]); after sort results= ( [1,2,3],[4,5,6],[7,8,9] );
I have one solutions, but it kinda defeats the purpose, it completely disassembles the array and then rebuilds it. This seems to me as this would be slow and cumbersome and also limited to square tables.
#!/usr/bin/perl use Data::Dumper; $sample= [ [5,7,2], [9,4,8], [1,6,3]]; $idx = $#$sample; for ($row=0; $row <= $idx; $row++) { if ( $#{$sample->[$row]} != $idx) {die "not a square table\n";} else { push @unsorted, @{$sample->[$row]};} } @sorted = sort { $a <=> $b } @unsorted; for ($row=0; $row <= $idx; $row++) { my $count = 0; while ($count <= $idx) { $sample->[$row][$count] = shift @sorted; $count++; } } print Dumper($sample);

Replies are listed 'Best First'.
Re: Sorting multi dimensional arrays
by arturo (Vicar) on Mar 14, 2001 at 21:49 UTC

    If you have a multidimensional array, and you want to sort out the 'flattened' version (I'm wondering why you'd want to do this, but whatever), the most straightforward way is to flatten it out by writing a loop that grabs each element in each array reference and then sort the result:

    my @flatarray; foreach (@twodimarray) { foreach my $element (@$_) { push @flatarray, $element; } } # for numeric data @flatarray = sort { $a <=> $b } @flatarray;

    This should work on *any* 2D array, whether the array references are all the same length or not.

    You might check on CPAN (search for "Array") to see if someone's written a module that can help you.

    Update I spoke too quickly ... so you want to reconstruct the array with the same dimensional structure as the original? well, take appropriate-sized slices of @flatarray and write them, as anonymous arrays, back into the original format (which is pretty much what you were doing). If you're dealing with more complex data (e.g. differing row lengths) you'll have to store the original row lengths (in an array) while you're flattening it out, and reconstruct the original array from that additional information.

    Philosophy can be made out of anything. Or less -- Jerry A. Fodor

Re: Sorting multi dimensional arrays
by japhy (Canon) on Mar 14, 2001 at 23:11 UTC
    You could sort each array reference individually, and then use some hybrid "merge" on them. But I'd suggest flattening them, and then unflattening them:
    my @flat = sort { $a <=> $b } map @$_, @orig; my @sorted = map [ $orig[3*$_ .. 3*$_+2] ], 0 .. $#flat/3;


    japhy -- Perl and Regex Hacker
(tye)Re: Sorting multi dimensional arrays
by tye (Sage) on Mar 15, 2001 at 04:12 UTC
    my $sample= [ [5,7,2], [9,4,8], [1,6,3] ]; my @widths= map 0+@$_, @$sample; my @sort= sort map @$_, @$sample; $sample= [ map { [ splice @sort, 0, $_ ] } @widths ];

    But if you really wanted to not pull it apart to sort it:

    use mapcar; my $sample= [ [5,7,2], [9,4,8], [1,6,3] ]; my @refs= sort {$$a cmp $$b} map \(@$_), @$sample; mapcar { my( $ref, $val )= @_; $$ref= $val; } \@refs, [ map $$_, @refs ];

    Which requires that you grab my mapcar.

            - tye (but my friends call me "Tye")
      sorting a list of names into alphabetical orders using arrays
        change cmp to <=>

        rdfield