Как новый набор тестов для показа, @ EriF89 все еще прав после всех этих лет:
$ 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
Здесь мы также сравниваем tuple
, который, как известно, быстрее, чем lists
(и использует меньше памяти) в некоторых случаях использования. В случае таблицы поиска, tuple
сработал не лучше.
И dict
, и set
работали очень хорошо. Это поднимает интересный момент, связанный с ответом @SilentGhost об уникальности: если у OP есть 10M значений в наборе данных, и неизвестно, есть ли в них дубликаты, тогда было бы целесообразно сохранить набор / указание его элементов параллельно с фактическим набором данных, и тестирование на существование в этом наборе / dict. Возможно, что 10M точек данных имеют только 10 уникальных значений, что намного меньше места для поиска!
Ошибка SilentGhost в отношении dicts на самом деле освещается тем, что можно использовать dict для корреляции дублированных данных (в значениях) в недублированный набор (ключи) и, таким образом, сохранить один объект данных для хранения всех данных, но при этом быть быстрым как поиск Таблица. Например, ключом dict может быть искомое значение, а значением может быть список индексов в воображаемом списке, в котором это значение произошло.
Например, если список исходных данных для поиска был l=[1,2,3,1,2,1,4]
, его можно было бы оптимизировать как для поиска, так и для памяти, заменив его следующим:
>>> 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]})
С этим диктом можно узнать:
- Если значение было в исходном наборе данных (т.е.
2 in d
возвращает True
)
- Где значение было в исходном наборе данных (то есть
d[2]
возвращает список индексов, где данные были найдены в исходном списке данных: [1, 4]
)