Ho un dizionario (potenzialmente piuttosto grande) e un elenco di chiavi "possibili". Voglio trovare rapidamente quali chiavi hanno valori corrispondenti nel dizionario. Ho trovato molte discussioni su single valori del dizionario here e here, ma nessuna discussione sulla velocità o più voci.Trovare tutte le chiavi in un dizionario da un elenco dato QUICKLY
Mi sono inventato quattro modi e, per i tre che funzionano meglio, paragono la loro velocità su campioni di dimensioni diverse di seguito: ci sono metodi migliori? Se le persone possono suggerire contendenti sensibili, li sottoporrò anche all'analisi sottostante.
liste di esempio e dizionari vengono creati nel modo seguente:
import cProfile
from random import randint
length = 100000
listOfRandomInts = [randint(0,length*length/10-1) for x in range(length)]
dictionaryOfRandomInts = {randint(0,length*length/10-1): "It's here" for x in range(length)}
Metodo 1: la parola chiave 'in'
:
def way1(theList,theDict):
resultsList = []
for listItem in theList:
if listItem in theDict:
resultsList.append(theDict[listItem])
return resultsList
cProfile.run('way1(listOfRandomInts,dictionaryOfRandomInts)')
32 chiamate di funzione in 0.018 secondi
Metodo 2: gestione degli errori:
def way2(theList,theDict):
resultsList = []
for listItem in theList:
try:
resultsList.append(theDict[listItem])
except:
;
return resultsList
cProfile.run('way2(listOfRandomInts,dictionaryOfRandomInts)')
32 chiamate di funzione in 0.087 secondi
Metodo 3: impostare intersezione:
def way3(theList,theDict):
return list(set(theList).intersection(set(theDict.keys())))
cProfile.run('way3(listOfRandomInts,dictionaryOfRandomInts)')
26 chiamate di funzione in 0,046 secondi
Metodo 4: Utilizzare Naive di dict.keys()
:
Questo è un ammonimento - è stato il mio primo tentativo e di gran lunga il più lento !
def way4(theList,theDict):
resultsList = []
keys = theDict.keys()
for listItem in theList:
if listItem in keys:
resultsList.append(theDict[listItem])
return resultsList
cProfile.run('way4(listOfRandomInts,dictionaryOfRandomInts)')
12 chiamate di funzione in 248.552 secondi
EDIT: Portare i suggerimenti dati nelle risposte nella stessa struttura che ho usato per la coerenza. Molti hanno notato che in Python 3.x si possono ottenere più guadagni in termini di prestazioni, in particolare i metodi basati sulla comprensione delle liste. Mille grazie per tutto l'aiuto!
Metodo 5: Modo migliore di eseguire intersezione (grazie jonrsharpe):
def way5(theList, theDict):
return = list(set(theList).intersection(theDict))
25 chiamate di funzione tra 0.037 secondi
Metodo 6: Elenco comprensione (grazie jonrsharpe):
def way6(theList, theDict):
return [item for item in theList if item in theDict]
24 chiamate di funzione in 0.020 secondi
Metodo 7: Utilizzo il keywor &
d (grazie jonrsharpe):
def way7(theList, theDict):
return list(theDict.viewkeys() & theList)
25 chiama 0,026 secondi
Per i metodi 1-3 e 5-7 li ho contati come sopra ed elenco/dizionari di lunghezza 1000, 10000, 100000, 1000000, 10000000 e 100000000 e mostrano un grafico del tempo di registrazione. In tutte le lunghezze, il metodo di intersezione e in-statement funziona meglio. I gradienti sono tutti circa 1 (forse un po 'più alti), indicando la scala O (n) o forse leggermente super-lineare.
Quale versione (s) di Python? In 2.x, dove 'dict.keys' restituisce una lista, mi aspetterei che' set (theDict.keys()) 'sia più lento di' set (theDict) ', per esempio, e' set (theList). intersezione (theDict) 'per essere più veloce di' set (theList) .intersection (set (theDict.keys())) '(e [' timeit'] (https://docs.python.org/2/library/timeit .html) concorda ...) – jonrsharpe
Inoltre, una [list comprehension] (https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions) è generalmente più veloce del ciclo e 'append'ing. – jonrsharpe
Se 2.x significa 2.7, userei 'dict.viewkeys' invece di' set (dict) 'o' set (dict.keys) '; questo ti dà un oggetto set-like supportato dalla tabella hash del dict esistente, invece di copiare tutte le chiavi in un'altra tabella hash. – abarnert