2012-05-01 22 views
11

Ho un referance array contenente hash (cioè @AOH)Ordinamento di un array di hash da più chiavi Perl

$arr_ref = [ { 'brand' => 'A', 
       'supplier' => 'X', 
       'PO' => '2' 
       }, 
       { 'brand' => 'B', 
       'supplier' => 'Y', 
       'PO' => '1'  
       }, 
       { 'brand' => 'B', 
       'supplier' => 'X', 
       'PO' => '2'   
       }, 
       { 'brand' => 'A', 
       'supplier' => 'X', 
       'PO' => '1' 
       }, 
       { 'brand' => 'B', 
       'supplier' => 'X', 
       'PO' => '1'   
       } 
]; 

voglio ordinare sulla base di tutti i tre tasti (ad esempio marca, fornitore e PO). L'ordine di smistamento deve essere prima marca, poi fornitore e infine PO.

serie referance dopo l'ordinamento dovrebbe essere:

$arr_ref = [ { 'brand' => 'A', 
       'supplier' => 'X', 
       'PO' => '1' 
       }, 
       { 'brand' => 'A', 
       'supplier' => 'X', 
       'PO' => '2' 
       }, 
       { 'brand' => 'B', 
       'supplier' => 'X', 
       'PO' => '1'   
       }, 
       { 'brand' => 'B', 
       'supplier' => 'X', 
       'PO' => '2'   
       },    
       { 'brand' => 'B', 
       'supplier' => 'Y', 
       'PO' => '1'  
       }, 
]; 

risposta

34

Dal <=> and cmp return 0 per indicare l'uguaglianza, e questo è falso, e perché gli operatori booleani logici del Perl restituiscono il valore invece di 0 o 1 di decidere, l'ordinamento per multipla chiavi è così facile come infilare confronti multipli con or o ||:

@$arr_ref = sort { $a->{brand} cmp $b->{brand} or 
        $a->{supplier} cmp $b->{supplier} or 
        $a->{PO}  <=> $b->{PO} 
       } @$arr_ref; 

sto supponendo che PO è un campo numerico, in modo da utilizzare per <=> invece di cmp.

+0

Grazie CJM. Ha funzionato :-) –

+0

Basta aggiungere uno scenario caso divertente. Ho dovuto assegnare il valore restituito dell'ordinamento {...} a un nuovo array invece di usare quello vecchio (@ $ arr_ref). Il primo ha restituito un riferimento vuoto ... ma non è ancora sicuro del perché. Grazie – mhz

+0

Molto molto utile, grazie! –

3

Il seguente dovrebbe ordinare il riferimento matrice e posizionare la matrice di nuovo nel $arr_ref:

$arr_ref = [sort by_brand_supplier_PO @$arr_ref]; 

sub by_brand_supplier_PO { 
    $a->{brand} cmp $b->{brand} || 
    $a->{supplier} cmp $b->{supplier} || 
    $a->{PO} <=> $b->{PO} 
} 
+0

Grazie ragazzi. Ha funzionato :-) –

1

È possibile utilizzare Sort::Key::Multi, distribuito con Sort :: chiave.

In questo caso, stiamo utilizzando ssikeysort, che si aspetta un blocco che restituisce una stringa, una stringa e un intero e che ordina i valori di tale tupla. (I s in ssi stand per archi e il i per intero.)

use Sort::Key::Multi qw(ssikeysort); 

@$arr_ref = ssikeysort { $_->{brand}, $_->{supplier}, $_->{PO} } @$arr_ref; 

è anche possibile utilizzare la variante sul posto, che utilizza meno memoria:

use Sort::Key::Multi qw(ssikeysort_inplace); 

ssikeysort_inplace { $_->{brand}, $_->{supplier}, $_->{PO} } @$arr_ref; 
Problemi correlati