Best ways to sort array of arrays?
Asked Answered
B

1

9

I need to sort an array of arrays; the .sort method seems to work by default. But what is a good way to sort by different indices of the inner arrays?

The array to be sorted is outer larger array: (birthday in 'mmddyy' format)

my @allRecords = [ [birthday1 firstName1 lastName1 [data1]
                   [birthday2 firstName2 lastName2 [data2] 
                   ...
                   [birthdayN firstNameN lastNameN [dataN] ];

@allRecords.sort by itself sorts by birthdays. 

What is a better way to sort by firstName or lastName or by data inside the inner arrays?

Balch answered 8/1, 2017 at 20:16 Comment(0)
H
9

The sort method takes a sub as optional argument. If its arity is 1, it uses the return value as comparison operands; if its arity is 2, you can manually do the comparison between elements however you see fit by returning one of Less, Same or More.

Given your example, we can sort by first name like this:

@allRecords.sort(*.[1]);

We can sort by last name, then first name, then birthday by doing the separate comparisons explicitly like this:

@allRecords.sort(-> $a, $b {
    $a[2] cmp $b[2] || $a[1] cmp $b[1] || $a[0] cmp $b[0]
});

or again implicitly by transforming the operands:

@allRecords.sort(*.[2...0]);

Transforming the birthday entry so we sort by year first is left as an exercise for the reader, but one way to do it would be to add something like

.comb(2).list.rotate(-1).join

where appropriate.

Horn answered 8/1, 2017 at 21:21 Comment(4)
You can sort by last name, then first name, then birthday like this: @a.sort: *[2...0]Milliard
2 more questions: (1) what is the difference between *.[1] vs *[1]; whatever star represents an inner array; should I use *[] instead of *.[] with the extra dot between * and []? (2) range operator .. or stub operator for a slice of the inner array? Thank you very much ! I am avidly learning perl6.Balch
@lisprogtor: re (1), there should not be any difference - I just find the former more readable; re (2), while range objects often behave like lists of integers, conceptually, they are a bit different (they are closer to mathematical intervals); in particular, you cannot count downwards using a range, and have to use the sequence operator ... insteadHorn
I see ! Thank you again Christoph ! To exit type 'exit' or '^D' > my $x = 1..5 1..5 > say $x 1..5 > say $x.list (1 2 3 4 5) > my $y = 5..1 5..1 > say $y.list () > my $z=5...1 (5 4 3 2 1) >Balch

© 2022 - 2024 — McMap. All rights reserved.