Como um novo conjunto de testes para mostrar @ EriF89 ainda está certo após todos esses anos:
$ 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
Aqui também comparamos a tuple
, que é conhecido por ser mais rápido do que lists
(e usa menos memória) em alguns casos de uso. No caso da tabela de pesquisa, a tuple
feira não melhorou.
Tanto dict
e set
teve um ótimo desempenho. Isso traz um ponto interessante relacionado à resposta do @SilentGhost sobre a exclusividade: se o OP possui valores de 10 milhões em um conjunto de dados e não se sabe se há duplicatas, vale a pena manter um conjunto / ditado de seus elementos em paralelo com o conjunto de dados real e testando a existência nesse conjunto / dict. É possível que os 10 milhões de pontos de dados tenham apenas 10 valores exclusivos, o que é um espaço muito menor para pesquisar!
O erro do SilentGhost sobre dicts é realmente esclarecedor porque se pode usar um dict para correlacionar dados duplicados (em valores) em um conjunto não duplicado (chaves) e, assim, manter um objeto de dados para armazenar todos os dados, mas ainda assim ser rápido como uma tabela de pesquisa. Por exemplo, uma chave dict pode ser o valor que está sendo pesquisado e o valor pode ser uma lista de índices em uma lista imaginária em que esse valor ocorreu.
Por exemplo, se a lista de dados de origem a ser pesquisada fosse l=[1,2,3,1,2,1,4]
, ela poderia ser otimizada para pesquisa e memória, substituindo-a por este ditado:
>>> 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]})
Com este ditado, pode-se saber:
- Se um valor estava no conjunto de dados original (ou seja,
2 in d
retorna True
)
- Onde o valor foi no conjunto de dados original (ie
d[2]
retorna lista de índices de onde os dados foram encontrados em lista de dados original: [1, 4]
)