Come una nuova serie di test per mostrare @ EriF89 è ancora giusto dopo tutti questi anni:
$ python -m timeit -s "l={k:k for k in xrange(5000)}" "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.84 msec per loop
$ python -m timeit -s "l=[k for k in xrange(5000)]" "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 573 msec per loop
$ python -m timeit -s "l=tuple([k for k in xrange(5000)])" "[i for i in xrange(10000) if i in l]"
10 loops, best of 3: 587 msec per loop
$ python -m timeit -s "l=set([k for k in xrange(5000)])" "[i for i in xrange(10000) if i in l]"
1000 loops, best of 3: 1.88 msec per loop
Qui confrontiamo anche a tuple
, che sono noti per essere più veloci di lists
(e usano meno memoria) in alcuni casi d'uso. Nel caso della tabella di ricerca, iltuple
premio non è migliore.
Sia il dict
che ilset
comportato molto bene. Questo fa emergere un punto interessante legato alla risposta di @SilentGhost sull'unicità: se l'OP ha valori 10M in un set di dati, ed è sconosciuto se ci sono duplicati in essi, varrebbe la pena mantenere un set / dict dei suoi elementi in parallelo con il set di dati effettivo e test per l'esistenza in tale set / dict. È possibile che i punti dati 10M abbiano solo 10 valori univoci, che è uno spazio molto più piccolo per la ricerca!
L'errore di SilentGhost sui dicts è in realtà illuminante perché si potrebbe usare un dict per correlare i dati duplicati (in valori) in un set non duplicato (chiavi), e quindi mantenere un oggetto dati per contenere tutti i dati, ma essere comunque veloce come una tabella di ricerca. Ad esempio, una chiave di dettatura potrebbe essere il valore che viene cercato e il valore potrebbe essere un elenco di indici in un elenco immaginario in cui si è verificato quel valore.
Ad esempio, se l'elenco dei dati di origine da cercare era l=[1,2,3,1,2,1,4]
, potrebbe essere ottimizzato sia per la ricerca che per la memoria sostituendolo con questo dict:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> l=[1,2,3,1,2,1,4]
>>> for i, e in enumerate(l):
... d[e].append(i)
>>> d
defaultdict(<class 'list'>, {1: [0, 3, 5], 2: [1, 4], 3: [2], 4: [6]})
Con questo detto, si può sapere:
- Se un valore era nel set di dati originale (ovvero
2 in d
restituisce True
)
- Dove il valore era di dati originale (cioè
d[2]
restituisce elenco degli indici in cui i dati è stato trovato nella lista dati originali: [1, 4]
)