Search code examples
arrayssortingperl2d

How do i sort a 2d array by a particular element, in Perl?


I have built a 2D array of scores and want to sort by the xth element (ie. the total). The first element identifies the player: Array looks like this;

$array[0][0] = "name one";
$array[0][1] = n1; # (some number)
$array[0][2] = n2; # (some number)
$array[0][3] = n3; # (some number)
$array[0][4] = n4; # (Total of above 3)

$array[1][0] = "name two";
$array[1][1] = n1; # (some number)
$array[1][2] = n2; # (some number)
$array[1][3] = n3; # (some number)
$array[1][4] = n4; # (Total of above 3)

how do i sort by the 4th element of each dimension? i tried

@new_array = sort { $a->[4] <=> $b->[4] || $a->[4] <=> $b->[4] } @array;

but got the original array back.


Solution

  • To sort arrayrefs in the array in decreasing order of their 5-th element

    my @sorted_by_largest_total = sort { $b->[4] <=> $a->[4] } @data;
    

    Or, if that "total" (the 5-th element) is indeed always the last element, better use index -1 for the last element. Then it doesn't matter if the number of players changes around, it still works.

    my @sorted_by_largest_total = sort { $b->[-1] <=> $a->[-1] } @data;
    

    I take it that the data is such that each arrayref has elements: name, then numbers (three as it stands in question's example), then total of those numbers.

    Note that it is simpler with a very useful Sort::Key module

    use Sort::Key qw(rnkeysort);  # Reverse-Numerical
    
    my @sorted_by_largest_total = rnkeysort { $_->[-1] } @data;
    

    The library has a large number of functions for all kinds of generic criteria (like reverse-numerical here), and the more complicated the sorting the more it simplifies the job.

    For example, if the scores to sort are strictly integer then there are ikeysort and rikeysort, and for unsigned integers -- likely for scores? -- there are ukeysort and rukeysort.