atapaka
atapaka

Reputation: 1360

perl sorting according to multiple columns (order of column matters)

I am trying to learn to sort a 2D array in perl by multiple columns so that the values are sorted in the order in which columns are specified, that is, first sort according to first column, then according to the second column etc. So that the table:

3  2
5  2
1  4

is sorted to

1  4
3  2
5  2

if the sort is in the order first column, second column or to

3  2
5  2
1  4

if the sort is according to the second column and then the first.

But it turns out I cannot even sort the table according to any column.

my @a = ([3,1,2], [3,5,4]);
my @b = sort {

    $a->[0] <=> $b->[0]

} @a;
print Dumper \@b

Does not do anything. Where am I making the mistake and how to achieve the above mentioned sort in proper column order?

Upvotes: 1

Views: 667

Answers (3)

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

I'm reading my @a = ([3,1,2], [3,5,4]); as it has 2 rows with 3 columns each. I'd store the table

3 3
1 5
2 4

as my @a = ([3, 3], [1, 5], [2, 4]); instead, which makes sorting simpler by using Short-circuit evaluation:

my @a = ([3, 3], [1, 5], [2, 4]);

my @b = sort {
    # Short-circuit evaluation:
    # if the values in the first column aren't equal, return the <=> result for
    # that, otherwise return the <=> result for the second column
    $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1];
} @a;

# @b is now ([1, 5], [2, 4], [3, 3])

Upvotes: 2

Jim Garrison
Jim Garrison

Reputation: 86774

You are sorting, just not the way you think you are. @a contains two objects, both array references. You are sorting those two references by the value of the first element in each referenced array.

Consider the following, using your example data:

@array = ([3,2],[5,2],[1,4]);
@sorted_01 = sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] } @array;
@sorted_10 = sort { $a->[1] <=> $b->[1] || $a->[0] <=> $b->[0] } @array;

The construct a<=>b || c<=>d compares a and b. If the result is non-zero (i.e. a and b are not equal) the expression evaluation ends. If they are equal however, evaluation continues and returns the result of comparing c and d.

Upvotes: 1

ikegami
ikegami

Reputation: 385789

Your code actually works.

The are passing to scalars two sort, the results of [3,1,2] and [3,5,4]. Then you sort these two elements based on the element of the referenced array ($a->[0] <=> $b->[0]). Why doesn't do anything? Well, because those arrays have the same value (3) as their first element.

If you the referenced arrays had different values in the first column (say [6,1,2] and [3,5,4]), you the one with the lowest value would have been returned first ([3,5,4] then [6,1,2]).

Upvotes: 1

Related Questions