2010-05-30 12 views
6

ho una serie perl di attività da svolgere che assomiglia a questo:personalizzato sorta di matrice in 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" 
); 

Questo primo numero è l'ID del compito. Se un'attività ha ([A-Z]) accanto a, ciò definisce la priorità dell'attività. Quello che voglio fare è sorta la matrice compiti in un modo che pone gli elementi prioritari primo (ed in ordine decrescente di priorità, dalla 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", 
); 

non posso usare un normale sort() a causa di quelle ID accanto alle attività, quindi presumo che sia necessaria una sorta di subroutine di ordinamento personalizzata. Tuttavia, la mia conoscenza di come farlo in perl in modo efficiente è minima.

Grazie, tutto.

risposta

12

Suona come si desidera che il Schwartzian transform:

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

"[" è il carattere dopo "Z"; dando questa "priorità" a oggetti altrimenti non specificati, li ordinerai dopo gli elementi prioritari.

In alternativa, e forse più facilmente afferrabile:

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

@Sean: Mentre una Trasformata di Schwartz è Groovy (e del caso), è molto difficile da seguire, specialmente dato che il PO è un principiante. – Zaid

+2

@Sean: questa è una soluzione interessante; grazie. Hai bisogno di scappare da ']' ater: alfa :? @Zaid - Anche se sono un principiante, @Sean mi ha dato quel link che spiega la trasformazione di Schwartz, quindi posso capirlo. :) – ABach

+0

@ABach: No, nessuna necessità di escape; questa è una classe di caratteri POSIX. (Vedi la pagina man di perlre.) ... Ma ho fatto un refuso ("[: alpha:]]" invece di "[[: alpha:]]", che ho appena corretto. – Sean

0

Ecco fisso @Sean's solution che utilizza sorta numerica per gli ID attività (quindi 10 ° compito va dopo 9 come dovrebbe):

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

Per qualcosa di minore, la modifica della risposta di Sean sembra sufficiente. Non ti manca esattamente il rappresentante. – rjh

+1

@rjh: leggi i commenti alla risposta di Sean l'OP non vuole la soluzione che ho fornito quindi Sarebbe sbagliato da parte mia modificare la risposta di Sean. D'altra parte la mia risposta è utile per gli altri che in futuro cercheranno "ordinamento personalizzato in perl". – jfs

3

Ecco un versione che è abbastanza esplicita su come funziona:

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

soluzione molto più semplice:

sort {($a =~ /\((.)\)/)[0] cmp ($b =~ /\((.)\)/)[0]} @todos; 
Problemi correlati