2010-02-08 9 views
6

Esiste un modo semplice (ovvero senza attivare la propria funzione di ordinamento) per ordinare gli elenchi paralleli senza copiare inutilmente in Python? Per esempio:Python ordinano array paralleli sul posto?

foo = range(5) 
bar = range(5, 0, -1) 
parallelSort(bar, foo) 
print foo # [4,3,2,1,0] 
print bar # [1,2,3,4,5] 

Ho visto gli esempi che utilizzano zip ma sembra sciocco per copiare tutti i dati da elenchi in parallelo ad una lista di tuple e viceversa se questo può essere facilmente evitato.

+1

Cosa pensi che questo parallelSort dovrebbe fare? Dai tuoi commenti risulta che ordina in ordine decrescente e aumenta in ordine crescente - giusto? –

+0

@Paul: ordina la barra e manipola foo in un attimo. – dsimcha

+0

Cosa darà 'parallelSort' se inizialmente' pippo' è '[2,4,6,10,8]' e 'bar' è' [3,7,9,5,1] '? – kennytm

risposta

0

Per raggiungere questo obiettivo, è necessario implementare il proprio tipo.

Tuttavia: la copia non necessaria fa veramente male all'applicazione? Spesso anche parti di Python mi sembrano inefficienti, ma sono abbastanza efficienti per quello di cui ho bisogno.

+0

Vedo il tuo punto di vista sull'ottimizzazione prematura, ma a volte (trattandosi di uno di questi casi) mi piace scrivere codice generico e sapere che se mai lo userò su un enorme set di dati o qualcosa che "funzionerà". In questo caso sono più preoccupato di rimanere senza memoria che di velocità. – dsimcha

+0

e non * il tuo genere * implica l'uso di 'zip',' dict', ecc.? – SilentGhost

+0

No. Supponi di implementare il tuo quicksort: puoi assicurarti di effettuare uno swap su entrambi gli elenchi. – bayer

3

C'è un modo semplice? Sì. Usa zip.

C'è un "modo semplice che non utilizza una variante di zip"? No.

Se volessi approfondire il motivo per cui ti opponi all'uso di zip, sarebbe utile. O stai copiando oggetti, nel qual caso Python copierà per riferimento, o stai copiando qualcosa di così leggero in una tupla leggera da non essere degno di ottimizzazione.

Se davvero non ti interessa la velocità di esecuzione, ma sono particolarmente preoccupato per qualche motivo sulla pressione della memoria, puoi impostare il tuo bubble sort (o il tuo algoritmo di scelta) nell'elenco delle chiavi che scambia sia l'elenco delle chiavi e il bersaglio elenca gli elementi quando fa uno scambio. Lo definirei il contrario di facile, ma sicuramente limiterebbe il tuo working set.

+3

Solo perché non riesci a pensare a un modo semplice che non usi zip non significa che non ce ne sia uno - vedi la mia risposta . :) –

+0

La tua risposta è zippare con un altro nome, quindi mi trovo dietro "non esiste un modo semplice che non usi una variante zip". Questa era una domanda stupida, tuttavia, quindi, se ordinando in memoria quali siano essenzialmente tuple di (sort_value, index) è preferibile ordinare tuple di (sort_value, target_value), bene. –

+0

"Zippare con un altro nome"? Non è certamente - non ha nulla a che fare con lo zipping, e non modifica affatto gli elementi originali. In effetti, non tocca nemmeno il secondo array. –

0

Qualsiasi soluzione che posso immaginare, a meno di introdurre una sorta da zero, utilizza indici, o un ditt, o qualcos'altro che non è in grado di salvarti la memoria. In ogni caso, l'utilizzo di zip aumenterà l'utilizzo della memoria solo di un fattore costante, quindi vale la pena assicurarsi che questo sia davvero un problema prima di una soluzione.

Se può essere un problema, potrebbero esserci soluzioni più efficaci. Poiché gli elementi di foo e bar sono così strettamente correlati, sei sicuro che la loro giusta rappresentazione non sia un elenco di tuple? Sei sicuro che non dovrebbero trovarsi in una struttura dati più compatta se stai esaurendo la memoria, come una matrice numpy o un database (l'ultimo dei quali è veramente buono in questo tipo di manipolazione)?

(anche, per inciso, itertools.izip può risparmiare un po 'di memoria nel zip, anche se è ancora finire con l'elenco zip completo sotto forma di lista come il risultato di ordinato.)

6

Ecco un modo semplice:

perm = sorted(xrange(len(foo)), key=lambda x:foo[x]) 

Questo genera un elenco di permutazioni - il valore in perm [i] è l'indice del esimo valore più piccolo nella foo. Quindi, è possibile accedere a entrambe le liste in ordine:

for p in perm: 
    print "%s: %s" % (foo[p], bar[p]) 

Avresti bisogno di punto di riferimento per scoprire se è più efficiente, anche se - dubito che fa molta differenza.

+0

Cambia 'range' in' xrange' se vuoi fare la differenza. A meno che tu non stia usando Python 3. –

+0

Hm, vero. O usa .sort invece di essere ordinato, ma questo rovina l'one-liner-ness. ;) –

+0

risulta che non è meglio che ordinarli fuori posto, perché 'sorted' allocherà avidamente molta memoria, ad es. 'ordinato (intervallo (10 ** 6), chiave = lambda x: x)'. (per intervallo intendo xrange, è stato modificato in python3) Noterai che una parte significativa della RAM scompare quando fai questo. Risulta che 'ordinato' è abbastanza intelligente da non ordinare' range', quindi fate attenzione ai test senza una funzione 'key ='. – ninjagecko

Problemi correlati