Jako nowy zestaw testów do pokazania, @ EriF89 wciąż ma rację po tych wszystkich latach:
$ 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
Tutaj również porównujemy a tuple
, o których wiadomo, że są szybsze niż lists
(i zużywają mniej pamięci) w niektórych przypadkach użycia. W przypadku tabeli przeglądowej rozszerzenietuple
nie wypadło lepiej.
Zarówno dict
iset
spisały się bardzo dobrze. Daje to interesującą kwestię związaną z odpowiedzią @SilentGhost na temat unikalności: jeśli OP ma 10M wartości w zestawie danych i nie wiadomo, czy są w nich duplikaty, warto byłoby równolegle zachować zestaw / dyktando jego elementów z rzeczywistym zbiorem danych i testowaniem istnienia w tym zbiorze / dyktandzie. Możliwe, że 10M punktów danych ma tylko 10 unikalnych wartości, co oznacza znacznie mniejszą przestrzeń do wyszukiwania!
Błąd SilentGhost dotyczący dykt jest w rzeczywistości naświetlony, ponieważ można użyć dyktu do skorelowania zduplikowanych danych (w wartościach) w nie powielony zestaw (klucze), a tym samym zachować jeden obiekt danych do przechowywania wszystkich danych, a jednocześnie być szybki jak tabela przeglądowa. Na przykład kluczem dict może być szukana wartość, a wartością może być lista indeksów na wyimaginowanej liście, na której ta wartość wystąpiła.
Na przykład, jeśli lista danych źródłowych do przeszukania była l=[1,2,3,1,2,1,4]
, można ją zoptymalizować zarówno pod kątem wyszukiwania, jak i pamięci, zastępując ją tym dyktowaniem:
>>> 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]})
Z tym dyktando można wiedzieć:
- Jeśli wartość znajdowała się w oryginalnym zbiorze danych (tj.
2 in d
Zwraca True
)
- Gdzie wartość była w oryginalnym zbiorze danych (czyli
d[2]
wraca lista indeksów, gdzie dane zostały znalezione w oryginalnej listy danych: [1, 4]
)