I have a perl array of to-do tasks that looks like this:
@todos = (
"1 (A) Complete online final @evm4700 t:2010-06-02",
"3 Write thank-you t:2010-06-10",
"4 (B) Clean t:2010-05-30",
"5 Donate to LSF t:2010-06-02",
"6 (A) t:2010-05-30 Pick up dry cleaning",
"2 (C) Call Chris Johnson t:2010-06-01"
);
That first number is the task's ID. If a task has ([A-Z]) next to, that defines the task's priority. What I want to do is sort the tasks array in a way that places the prioritized items first (and in order of descending priority, from A - Z):
@todos = (
"1 (A) Complete online final @evm4700 t:2010-06-02",
"6 (A) t:2010-05-30 Pick up dry cleaning",
"4 (B) Clean t:2010-05-30",
"2 (C) Call Chris Johnson t:2010-06-01"
"3 Write thank-you t:2010-06-10",
"5 Donate to LSF t:2010-06-02",
);
I cannot use a regular sort()
because of those IDs next to the tasks, so I'm assuming that some sort of customized sorting subroutine is needed. However, my knowledge of how to do this efficiently in perl is minimal.
Thanks, all.
sort() function in Perl is used to sort a list with or without the use of method of sorting. This method can be specified by the user in the form of subroutines or blocks. If a subroutine or block is not specified then it will follow the default method of sorting.
Perl has two operators that behave this way: <=> for sorting numbers in ascending numeric order, and cmp for sorting strings in ascending alphabetic order. By default, sort uses cmp -style comparisons.
Just use: @sorted = sort { $a <=> $b } @unsorted; The sort function accepts a custom comparison function as its first argument, in the form of a code block.
Sounds like you want the Schwartzian transform:
@todos =
map { $_->[0] }
sort { $a->[1] cmp $b->[1] or $a->[0] cmp $b->[0] }
map { [ $_, /^\d+ \(([[:alpha:]])\)/ ? $1 : "[" ] }
@todos;
"[" is the character after "Z"; giving this "priority" to otherwise unprioritized items will sort them after the prioritized items.
Alternately, and perhaps more easily graspable:
@todos =
map { substr $_, 1 }
sort
map { (/^\d+ \(([[:alpha:]])\)/ ? $1 : "[") . $_ }
@todos;
Here's a version that is fairly explicit about how it works:
my @sorted_todos = sort {
my ($right_prio) = ($b =~ /^\d+\s+\(([A-Z])\)/);
return -1 unless defined $right_prio;
my ($left_prio) = ($a =~ /^\d+\s+\(([A-Z])\)/);
return 1 unless defined $left_prio;
return $left_prio cmp $right_prio;
} @todos;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With