2010-05-30 14 views
6

mam perla tablicę do wykonania zadań, które wygląda następująco:Niestandardowe sortowanie tablicy w Perl

@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" 
); 

To jest pierwszy numer ID zadania jest. Jeśli zadanie ma ([A-Z]) obok, określa priorytet zadania. Co chcę zrobić, to rodzaj tablicy zadania w sposób, który stawia priorytetowych elementów pierwszy (i w kolejności malejącej, od 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", 
); 

Nie mogę użyć zwykłego sort() powodu tych identyfikatorów obok zadań, więc zakładam, że potrzebny jest jakiś niestandardowy podprogram sortowania. Jednak moja wiedza na temat tego, jak zrobić to skutecznie w perlu jest minimalna.

Dzięki, wszystkie.

Odpowiedz

12

Brzmi jak chcesz Schwartzian transform:

@todos = 
    map { $_->[0] } 
    sort { $a->[1] cmp $b->[1] or $a->[0] cmp $b->[0] } 
    map { [ $_, /^\d+ \(([[:alpha:]])\)/ ? $1 : "[" ] } 
    @todos; 

"[" jest postać po "Z"; nadanie tego "priorytetu" innym pozycjom niepriorytetycznym spowoduje ich sortowanie po priorytetowych pozycjach.

Alternatywnie, i być może łatwiej chwytania:

@todos = 
    map { substr $_, 1 } 
    sort 
    map { (/^\d+ \(([[:alpha:]])\)/ ? $1 : "[") . $_ } 
    @todos; 
+1

@Sean: Podczas Transformacja Schwartza jest Groovy (i jest), to jest bardzo trudne do naśladowania, zwłaszcza biorąc pod uwagę, że PO jest początkującym. – Zaid

+2

@Sean - jest to fajne rozwiązanie; Dziękuję Ci. Czy musisz uciec z tego ']' ater: alpha :? @ Zaid - mimo że jestem początkującym, @Sean dał mi ten link, który wyjaśnia transformację Schwartzian, więc mogę ją zrozumieć. :) – ABach

+0

@ABach: Nie, nie ma potrzeby ucieczki; jest to klasa znaków POSIX. (Zobacz stronę perlre man.) ... Ale zrobiłem literówkę ("[: alpha:]]" zamiast "[[: alpha:]]", które właśnie naprawiłem – Sean

0

Oto stałym @Sean's solution że używa swego liczbową dla identyfikatorów zadań (tym samym 10-ci zadanie idzie po 9 tak jak powinien):

my @sorted_todos = map { $_->[0] } 
    sort { $a->[1][1] cmp $b->[1][1] # A 
         || 
      $a->[1][0] <=> $b->[1][0] # 1 
    } map { [ $_, /^(\d+) \(([[:alpha:]])\)/ ? [$1, $2] : [0, "zz"]] } @todos; 
+1

Dla czegoś nieistotnego, edycja odpowiedzi Seana wydaje się wystarczająca. Nie brakuje ci dokładnie rep. – rjh

+1

@rjh: przeczytaj komentarze na odpowiedź Seana OP nie chce rozwiązania, które podałem, więc byłoby źle z mojej strony, aby edytować odpowiedź Seana. Z drugiej strony moja odpowiedź jest przydatna dla innych, którzy będą szukać "niestandardowego sortowania w perlu" w przyszłości. – jfs

3

Oto wersja, która jest dość jednoznaczna, jak to działa:

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; 
0
use Sort::Key 'keysort'; 

my @sorted = keysort { /^\d+\s+\(([A-Z])\)/ ? $1 : 'ZZ' } @todos; 
0

znacznie prostsze rozwiązanie:

sort {($a =~ /\((.)\)/)[0] cmp ($b =~ /\((.)\)/)[0]} @todos; 
Powiązane problemy