2013-02-27 13 views
28

Se ho un elenco python che ha molti duplicati e voglio scorrere ogni elemento, ma non attraverso i duplicati, è meglio usare un set (come in set(mylist), o trovare un altro modo per creare un elenco senza duplicati? stavo pensando di appena scorrendo la lista e il controllo dei duplicati, ma ho pensato che è quello che set() fa quando è inizializzato.Migliore/Più veloce per passare da un set o un elenco?

Quindi, se mylist = [3,1,5,2,4,4,1,4,2,5,1,3] e ho davvero voglia di scorrere [1,2,3,4,5] (ordine non importa), dovrei usare set(mylist) o qualcos'altro?

Un'alternativa è possibile nell'ultimo esempio, poiché l'elenco contiene ogni numero intero tra il suo minimo e il mio valore dell'asse, ho potuto passare attraverso range(min(mylist),max(mylist)) o tramite set(mylist). Dovrei in generale cercare di evitare l'uso del set in questo caso? Inoltre, trovare min e è più lento della semplice creazione di set?


Nel caso nell'ultimo esempio, il set è più veloce:

from numpy.random import random_integers 
ids = random_integers(1e3,size=1e6) 

def set_loop(mylist): 
    idlist = [] 
    for id in set(mylist): 
     idlist.append(id) 
    return idlist 

def list_loop(mylist): 
    idlist = [] 
    for id in range(min(mylist),max(mylist)): 
     idlist.append(id) 
    return idlist 

%timeit set_loop(ids) 
#1 loops, best of 3: 232 ms per loop 

%timeit list_loop(ids) 
#1 loops, best of 3: 408 ms per loop 
+0

Perché non provarlo? –

+2

@JoelCornett done :) – askewchan

+0

Ti aspetti che questa differenza di velocità sia importante in qualsiasi programma tu scriva mai? Mantenere le cose in 'numpy', usando un genexp invece di costruire un' lista' di milioni di elementi solo per iterare (e usare 'xrange' invece di' range' se questo è Py2), cercando di fare loop stretti in C di Python (ad esempio, 'idlist = range (...)' invece di un ciclo 'for' che fa la stessa cosa), ecc. tutti renderanno gli ordini di grandezza più differenti. – abarnert

risposta

33

basta usare un set. La sua semantica è esattamente ciò che desideri: una collezione di oggetti unici.

Tecnicamente verrà ripetuto l'elenco due volte: una volta per creare il set, una volta per il ciclo effettivo. Ma faresti altrettanto lavoro o più con qualsiasi altro approccio.

+0

utilizzando un generatore e un set si interromperà solo una volta, dai un'occhiata alla mia risposta mi piacerebbe la tua opinione. @ Eevee – Cherif

3

Per semplicità: newList = list(set(oldList))

Ma ci sono opzioni migliori là fuori, se si desidera ottenere la velocità/ordine/ottimizzazione invece: http://www.peterbe.com/plog/uniqifiers-benchmark

+3

Non c'è una buona ragione per tornare a una lista. Ha già perso l'ordine degli elementi quando lo ha convertito in un set, quindi non c'è motivo per non rimanere con il set. – ThiefMaster

+0

@ThiefMaster Ci sono motivi per voler tornare a un elenco, principalmente le prestazioni. Gli elenchi sono molto più veloci per l'iterazione di un set e mantenendo un attributo interno per ogni elemento puoi facilmente riconvertirlo in un elenco e ordinarlo nell'ordine corretto. – Flipper

9

set è quello che volete, così si dovrebbe usare set . Cercare di essere intelligenti introduce dei bug sottili come dimenticare di aggiungere uno a max(mylist)! Codice difensivo. Preoccupati per ciò che è più veloce quando si determina che è troppo lento.

range(min(mylist), max(mylist) + 1) # <-- don't forget to add 1 
+0

mi piacerebbe che qui la tua opinione sulla mia risposta è veloce quando ci occupiamo di una grande lista. – Cherif

4

Mentre un set può essere ciò che si desidera la struttura-saggio, la domanda è che cosa è più veloce. Una lista è più veloce. Il tuo codice di esempio non si confronta con precisione set vs list perché si sta convertendo da un elenco ad un insieme inset_loop, e poi si sta creando il list sarete loop attraverso inlist_loop. Il set e la lista di eseguire iterazioni attraverso dovrebbero essere costruite ed in memoria prima del tempo, e semplicemente in loop con per vedere quale struttura di dati è più veloce a iterazione:

ids_list = range(1000000) 
sids_set = set(ids) 
def f(x): 
    for i in x: 
     pass 

%timeit f(ids_set) 
#1 loops, best of 3: 214 ms per loop 
%timeit f(ids_list) 
#1 loops, best of 3: 176 ms per loop 
1

I, l'elenco è variare grande loop due volte su di esso sarà Prendiamo molto tempo e molto altro nel secondo tempo in cui esegui il ciclo di un set non di un elenco e, come sappiamo, il iterating su un set è più lento di un elenco.

penso che sia necessario il potere di generator e set.

def first_test(): 

    def loop_one_time(my_list): 
     # create a set to keep the items. 
     iterated_items = set() 
     # as we know iterating over list is faster then list. 
     for value in my_list: 
      # as we know checking if element exist in set is very fast not 
      # metter the size of the set. 
      if value not in iterated_items: 
       iterated_items.add(value) # add this item to list 
       yield value 


    mylist = [3,1,5,2,4,4,1,4,2,5,1,3] 

    for v in loop_one_time(mylist):pass 



def second_test(): 
    mylist = [3,1,5,2,4,4,1,4,2,5,1,3] 
    s = set(mylist) 
    for v in s:pass 


import timeit 

print(timeit.timeit('first_test()', setup='from __main__ import first_test', number=10000)) 
print(timeit.timeit('second_test()', setup='from __main__ import second_test', number=10000)) 

fuori messo:

0.024003583388435043 
    0.010424674188938422 

Nota: questo ordine tecnica è garantita

Problemi correlati