2010-05-28 5 views
36

Considera una lista Python my_list contenente ['foo', 'foo', 'bar'].Qual è il modo più pulito di fare un ordinamento più uniq su un elenco Python?

Qual è il modo più Pythonic per uniquify e ordinare un elenco?
(penso cat my_list | sort | uniq)

Questo è il modo in cui attualmente lo faccio e mentre funziona sono sicuro che ci sono modi migliori per farlo.

my_list = [] 
... 
my_list.append("foo") 
my_list.append("foo") 
my_list.append("bar") 
... 
my_list = set(my_list) 
my_list = list(my_list) 
my_list.sort() 
+0

Possibile dupl icate di [Come rimuovere i duplicati dall'elenco Python e mantenere l'ordine?] (http://stackoverflow.com/questions/479897/how-to-remove-duplicates-from-python-list-and-keep-order) – sampablokuper

risposta

73
my_list = sorted(set(my_list)) 
+9

Nota che questo funziona solo per i tipi hasable, quindi per esempio questo non funzionerà sugli elenchi. – taleinat

+0

Vale la pena ricordare che questo fa tutto in memoria mentre 'sort' (di solito?) Sa di persistere su disco. Se stai applicando questo a una grande porzione di dati, dovrebbe fallire su 'MemoryError'. Buona risposta però :) –

+0

@ReutSharabani: No, il diverso è che il metodo 'sort()' funziona sul posto e quindi non richiede un'assegnazione aggiuntiva. –

-4

non posso dire che è un modo pulito per farlo, ma solo per divertimento:

my_list = [x for x in sorted(my_list) if not x in locals()["_[1]"]] 
+6

Questo è brutto, magico e inutilmente quadratico. –

+0

Certo, è solo per divertimento, come ho notato. – andreypopp

5

La soluzione semplice è fornita da Ignacio- sorted(set(foo)).

Se si dispone di dati univoci, esiste una ragionevole possibilità che non si desidera solo eseguire sorted(set(...)) ma piuttosto memorizzare un set tutto il tempo e occasionalmente estrarre una versione ordinata dei valori. (A quel punto, inizia a sembrare il genere di cose che la gente usa spesso anche per un database.)

Se si dispone di un elenco ordinato e si desidera controllare l'appartenenza su logaritmico e aggiungere un elemento nel caso peggiore di tempo lineare , è possibile utilizzare lo bisect module.

Se si desidera mantenere sempre questa condizione e si desidera semplificare le operazioni o migliorare le prestazioni, è possibile considerare blist.sortedset.

+0

Considera [contenitori ordinati] (http://www.grantjenks.com/docs/sortedcontainers/). [SortedSet] (http://www.grantjenks.com/docs/sortedcontainers/sortedset.html) invece di blist. È [più veloce] (http://www.grantjenks.com/docs/sortedcontainers/performance.html) e pure-Python. – GrantJ

2

Altri hanno menzionato l'ordinamento (set (my_list)), che funziona per valori hashable come stringhe, numeri e tuple, ma non per tipi non selezionabili come elenchi.

Per ottenere un elenco ordinato di valori di qualsiasi tipo ordinabili, senza duplicati:

from itertools import izip, islice 
def unique_sorted(values): 
    "Return a sorted list of the given values, without duplicates." 
    values = sorted(values) 
    if not values: 
     return [] 
    consecutive_pairs = izip(values, islice(values, 1, len(values))) 
    result = [a for (a, b) in consecutive_pairs if a != b] 
    result.append(values[-1]) 
    return result 

Questo può essere ulteriormente semplificato utilizzando il "coppie" o ricette "unique_justseen" dal itertools documentation.

10
# Python ≥ 2.4 
# because of (generator expression) and itertools.groupby, sorted 

import itertools 

def sort_uniq(sequence): 
    return (x[0] for x in itertools.groupby(sorted(sequence))) 

veloce:

import itertools, operator 
import sys 

if sys.hexversion < 0x03000000: 
    mapper= itertools.imap # 2.4 ≤ Python < 3 
else: 
    mapper= map # Python ≥ 3 

def sort_uniq(sequence): 
    return mapper(
     operator.itemgetter(0), 
     itertools.groupby(sorted(sequence))) 

Entrambe le versioni restituiscono un generatore, così si potrebbe desiderare di fornire il risultato per il tipo di lista:

sequence= list(sort_uniq(sequence)) 

Si noti che questo non funziona con articoli lavabili anche:

>>> list(sort_uniq([[0],[1],[0]])) 
[[0], [1]] 
+1

Se stai usando python3: Py3 map e in Py2 itertools.imap fa esattamente la stessa cosa. (In Py3 iter (mappa (...)) è ridondante.) –

+0

Questo è molto meglio della risposta accettata se si dispone di una grande quantità di dati. +1 –

+0

@TheDemz la risposta necessaria tenendo conto del fatto che Python 3 è molto più comune ora di allora; Grazie – tzot