2013-01-04 21 views
5

Scusa se è stata fornita una risposta altrove; Ho provato a cercare, ma non ho trovato nulla che risponda alla mia domanda (o forse ho, ma non ho capito) ...Python - Ordinamento di elementi in un elenco di elenchi

Sono abbastanza nuovo per Python (v2.6.2) e ho una lista di liste contenenti valori in virgola mobile che sembra qualcosa di simile alla seguente (tranne la cosa completo ha 2+ milioni di voci per ogni lista):

cat = [[152.123, 150.456, 151.789, ...], [4.123, 3.456, 1.789, ...], [20.123, 22.456, 21.789, ...]] 

Ora quello che vorrei fare è una sorta tutti e 3 gli elenchi da ordine crescente degli elementi della 3a lista, tale che ottengo:

cat_sorted = [[152.123, 151.789, 150.456, ...], [4.123, 1.789, 3.456, ...], [20.123, 21.789, 22.456, ...]] 

Ho provato alcune cose, ma non mi danno quello che sto cercando (o forse le sto usando in modo errato). C'è un modo per fare quello che sto cercando e, in tal caso, qual è il più semplice & più veloce (considerando che ho 3 x 2 milioni di voci)? C'è un modo di ordinare una lista usando un'altra?

+0

Basta chiedersi che tipo di problema è e Python si adatta davvero a questo? Non ho visto alcun caso di utilizzo di python per attività con tali quantità di dati .. – Ixanezis

risposta

8

questo sta per essere doloroso, ma utilizzando python di default si hanno 2 opzioni:

  • decorare il 1 ° e 2 liste con enumerate(), quindi ordinare questi utilizzando l'indice di riferimento a valori dal 3 lista :

    cat_sorted = [ 
        [e for i, e in sorted(enumerate(cat[0]), key=lambda p: cat[2][p[0]])], 
        [e for i, e in sorted(enumerate(cat[1]), key=lambda p: cat[2][p[0]])], 
        sorted(cat[2]) 
    ] 
    

    anche se può aiutare a risolvere cat[2] sul posto invece di utilizzare sorted(); non puoi andare in giro usando sorted() per gli altri due.

  • zip() tre liste insieme, quindi ordinare sul terzo elemento di questa nuova lista di liste, poi zip() di nuovo per tornare alla struttura originaria:

    from operator import itemgetter 
    cat_sorted = zip(*sorted(zip(*cat), key=itemgetter(2))) 
    

Né sarà una performance buster, non con liste di python semplici di milioni di numeri.

+0

questa è un'ottima soluzione! –

+0

Una volta capito cosa intendeva OP e come la descrizione corrispondesse all'ingresso e all'uscita del campione, la mia mente balzò immediatamente all'approccio 'zip' che mostri. La descrizione del problema fornita suggerisce che i dati non sono realmente organizzati correttamente per cominciare; 'zip' si avvicina a quello elegantemente. –

+0

Brillante. La seconda soluzione con il comando zip funziona perfettamente. Grazie per l'aiuto! :) – Shanagar

4

Se si desidera utilizzare una libreria aggiuntiva, suggerisco Python Pandas. Ha un oggetto DataFrame simile a R data.frame e accetta un elenco di liste nel costruttore, che creerà un array di dati a 3 colonne. Quindi è possibile utilizzare facilmente la funzione integrata pandas.DataFrame.sort per ordinare dalla terza colonna (crescente o decrescente).

Ci sono molti modi in Python per farlo, ma vista la dimensione del problema, l'utilizzo delle funzioni ottimizzate in Panda è un approccio migliore. E se hai bisogno di qualsiasi tipo di statistica aggregata dai tuoi dati ordinati, allora Pandas è un gioco da ragazzi per questo.

+0

+1 per l'utilizzo di Panda: è quello che stavo scrivendo. Le altre risposte sono corrette ma per insiemi di dati così grandi una libreria come Pandas è ciò che si vuole veramente. – Iguananaut

2

L'approccio generale che vorrei fare era fare un schwartzian transform sul tutto.

Comprimere le tre liste insieme in un elenco di tuple.

Ordinare le tuple usando il terzo elemento come chiave.

iterare sopra la nuova lista di tuple e riempire nuovamente le tre liste.

1

Per motivi di completamento, una soluzione che utilizza NumPy:

import numpy as np 

cat = [[152.123, 150.456, 151.789], 
     [4.123, 3.456, 1.789], 
     [20.123, 22.456, 21.789]] 

cat = np.array(cat) 
cat_sorted = cat[:, cat[2].argsort()] 

print cat_sorted 
[[ 152.123 151.789 150.456] 
[ 4.123 1.789 3.456] 
[ 20.123 21.789 22.456]] 
0

Ecco un altro modo per farlo sulla base delle ottime risposte da Martijn Pieters e pcalcao

def sort_by_last(ll): 
    """ 
     >>> sort_by_last([[10, 20, 30], [3, 2, 1]]) 
     [[30, 20, 10], [1, 2, 3]] 

     >>> sort_by_last([[10, 20, 30], [40, 50, 60], [3, 2, 1]]) 
     [[30, 20, 10], [60, 50, 40], [1, 2, 3]] 

     >>> sort_by_last([[10, 20, 30], [40, 50, 60], [1, 1, 1]]) 
     [[10, 20, 30], [40, 50, 60], [1, 1, 1]] 

     >>> sort_by_last([[10, 20, 30], [40, 50, 60], [1, 3, 1]]) 
     [[10, 30, 20], [40, 60, 50], [1, 1, 3]] 

     >>> sort_by_last([[152.123, 150.456, 151.789], [4.123, 3.456, 1.789], [20.123, 22.456, 21.789]]) 
     [[152.123, 151.789, 150.456], [4.123, 1.789, 3.456], [20.123, 21.789, 22.456]] 
    """ 
    return [sorted(x, key=lambda y: ll[-1][x.index(y)]) for x in ll] 

Il grande stringa di lì è una docstring con doctest, per testare la funzione copiarlo in un file ed eseguirlo con python -m doctest -v <file>

+0

La puntura qui è 'x.index()' che renderà l'ordinamento piuttosto lento per le liste di grandi dimensioni –

0

Qui, keys è un elenco ordinato di indici.

keys = sorted(range(len(cat[2])), key=cat[2].__getitem__) 
cat_sorted = [[cat[i][k] for k in keys] for i in range(3)] 
Problemi correlati