2010-06-19 7 views
6

sto cercando più veloce/modo efficace per l'eliminazione di alcuni tasti in un pitone dictmodo più veloce di eliminare alcune chiavi da dict in Python

Qui ci sono alcune opzioni

for k in somedict.keys(): 
    if k.startswith("someprefix"): 
     del somedict[k] 

o

dict((k, v) for (k, v) in somedict.iteritems() if not k.startswith('someprefix')) 

Logicamente, il primo snippet dovrebbe essere più veloce su dict più piccoli, non crea una copia di un dict ma crea un elenco di tutte le chiavi, tuttavia le doppie ricerche e la ricostruzione di dettare richiedono molto tempo. Mentre il secondo è più veloce su dit più grandi, ma richiede 2x memoria in più. Ho verificato la mia ipotesi in un piccolo benchmark.

Qualcosa di più veloce?

+0

@Adam: No, non è possibile. Non è possibile aggiungere o rimuovere elementi da un dettato che si sta iterando. –

+0

Utilizzare un trie. ___ – kennytm

+0

@ Ignacio: grazie, commento eliminato. – bernie

risposta

9

Se il comando è abbastanza grande, potrebbe essere opportuno generare un nuovo dict completamente nuovo.

dict((k, v) for (k, v) in somedict.iteritems() if not k.startswith('someprefix')) 
+0

Grazie, la mia prima soluzione era esattamente la tua, interessante per benchmark che è più veloce. – HardQuestions

11

non solo è del più facilmente comprensibile, ma sembra un po 'più veloce di pop():

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "for k in d.keys():" " if k.startswith('f'):" " del d[k]" 
1000000 loops, best of 3: 0.733 usec per loop 

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "for k in d.keys():" " if k.startswith('f'):" " d.pop(k)" 
1000000 loops, best of 3: 0.742 usec per loop 

Edit: grazie ad Alex Martelli per fornire le istruzioni su come fare questo benchmarking. Spero di non essere scivolato da nessuna parte.

Prima misura il tempo necessario per la copia:

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "d1 = d.copy()" 
1000000 loops, best of 3: 0.278 usec per loop 

di Riferimento in dict copiato:

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "d1 = d.copy()" "for k in d1.keys():" " if k.startswith('f'):" " del d1[k]" 
100000 loops, best of 3: 1.95 usec per loop 

$ python -m timeit -s "d = {'f':1,'foo':2,'bar':3}" "d1 = d.copy()" "for k in d1.keys():" " if k.startswith('f'):" " d1.pop(k)" 
100000 loops, best of 3: 2.15 usec per loop 

Sottraendo il costo della copia, otteniamo 1.872 usec per pop() e 1.672 per del.

+0

Pensi che pop sia più veloce dell'eliminazione? – HardQuestions

+0

@Mike: aggiunto benchmark per mostrare che la tua strada è leggermente più veloce dell'uso di 'pop()' mentre è anche più leggibile IMO. – bernie

+0

@Adam Bernier solo perché pop restituisce un valore mentre non lo è. Con valori maggiori o maggiori, la differenza dovrebbe essere notevole. – HardQuestions

Problemi correlati