Eu tenho cerca de 10 milhões de valores que preciso colocar em algum tipo de tabela de pesquisa, então fiquei imaginando qual seria uma lista ou ditado mais eficiente .
Eu sei que você pode fazer algo assim para ambos:
if something in dict_of_stuff:
pass
e
if something in list_of_stuff:
pass
Meu pensamento é que o ditado será mais rápido e mais eficiente.
Obrigado pela ajuda.
EDIT 1
Pouco mais informações sobre o que estou tentando fazer. Problema de Euler 92 . Estou fazendo uma tabela de consulta para ver se um valor calculado já foi calculado.
EDIT 2
Eficiência para procurar.
EDIT 3
Não há valores associados ao valor ... então um conjunto seria melhor?
python
performance
Não
fonte
fonte
Respostas:
Rapidez
As pesquisas nas listas são O (n), as pesquisas nos dicionários são amortizadas O (1), em relação ao número de itens na estrutura de dados. Se você não precisar associar valores, use conjuntos.
Memória
Dicionários e conjuntos usam hash e usam muito mais memória do que apenas para armazenamento de objetos. De acordo com AM Kuchling no Beautiful Code , a implementação tenta manter o hash 2/3 cheio, para que você possa perder bastante memória.
Se você não adicionar novas entradas rapidamente (o que você faz, com base na sua pergunta atualizada), pode valer a pena classificar a lista e usar a pesquisa binária. É O (log n) e provavelmente é mais lento para seqüências de caracteres, impossível para objetos que não possuem uma ordem natural.
fonte
Um ditado é uma tabela de hash, portanto é muito rápido encontrar as chaves. Então, entre dict e list, dict seria mais rápido. Mas se você não tem um valor para associar, é ainda melhor usar um conjunto. É uma tabela de hash, sem a parte "table".
EDIT: para sua nova pergunta, SIM, um conjunto seria melhor. Basta criar 2 conjuntos, um para as seqüências terminadas em 1 e outro para as seqüências terminadas em 89. Resolvi esse problema com êxito usando conjuntos.
fonte
set()
é exatamente o que você quer. O (1) pesquisas e menor que um ditado.fonte
Fiz alguns testes de desempenho e verifica-se que o dict é mais rápido que a lista e o conjunto para grandes conjuntos de dados, executando o python 2.7.3 em uma CPU i7 no linux:
python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'
10 loops, o melhor de 3: 64,2 ms por loop
python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'
10000000 loops, o melhor de 3: 0,0759 usec por loop
python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'
1000000 loops, o melhor de 3: 0,226 usec por loop
Como você pode ver, o dict é consideravelmente mais rápido que a lista e cerca de 3 vezes mais rápido que o definido. Em alguns aplicativos, você ainda pode querer escolher um conjunto para a beleza dele. E se os conjuntos de dados forem realmente pequenos (<1000 elementos), as listas terão um desempenho muito bom.
fonte
-s
opção é configurar otimeit
ambiente, ou seja, ele não conta no tempo total. A-s
opção é executada apenas uma vez. No Python 3.3, obtenho esses resultados: gen (intervalo) -> 0,229 usec, lista -> 157 msec, dict -> 0,0806 usec, conjunto -> 0,0807 usec. Definir e ditar o desempenho é o mesmo. Dict no entanto demora um pouco mais para inicializar do que set (tempo total 13.580s v 11.803s.)python -mtimeit -s "d=set(range(10**7))" "5*10**6 in d"
uso do Python 3.6.0 (10000000 loops, o melhor de 3: 0,0608 usec por loop), aproximadamente o mesmo que o benchmark dict, então obrigado pelo seu comentário.Você quer um ditado.
Para listas (não ordenadas) em Python, a operação "in" requer tempo O (n) --- não é bom quando você tem uma grande quantidade de dados. Um ditado, por outro lado, é uma tabela de hash, portanto, você pode esperar o tempo de pesquisa de O (1).
Como outros observaram, você pode escolher um conjunto (um tipo especial de ditado), se tiver apenas chaves em vez de pares chave / valor.
Palavras-chave:
fonte
in
operador aplicado a uma lista classificada tem um desempenho melhor do que quando aplicado a uma lista não classificada (para uma pesquisa de um valor aleatório)? (Eu não acho que se eles são implementados internamente como vetores ou como nós em uma lista ligada é relevante.)se os dados forem únicos, set () será o mais eficiente, mas com dois dict (o que também exige exclusividade, oops :)
fonte
Como um novo conjunto de testes para mostrar @ EriF89 ainda está certo após todos esses anos:
Aqui também comparamos a
tuple
, que é conhecido por ser mais rápido do quelists
(e usa menos memória) em alguns casos de uso. No caso da tabela de pesquisa, atuple
feira não melhorou.Tanto
dict
eset
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:Com este ditado, pode-se saber:
2 in d
retornaTrue
)d[2]
retorna lista de índices de onde os dados foram encontrados em lista de dados original:[1, 4]
)fonte
Na verdade, você não precisa armazenar 10 milhões de valores na tabela, portanto não é grande coisa de qualquer maneira.
Dica: pense no tamanho do seu resultado após a primeira soma dos quadrados. O maior resultado possível será muito menor que 10 milhões ...
fonte