8 dígitos parecem pequenos e podem resultar em colisões de hashes se você tiver um grande número de registros. stackoverflow.com/questions/1303021/…
DhruvPathak de
Use hashlib, pois o hash tem outro propósito!
arquitetônico de
2
Qualquer número finito de dígitos resultará em colisões para números suficientemente grandes de itens hash, é por isso que você não deve tratá-los como chaves exclusivas - isso tende a se transformar no problema de aniversário.
Alex North-Keys de
1
Eu escolhi "CityHash" para sequências de hash para inteiros de 19 dígitos (inteiros de 64 bits), esperando que isso leve a menos colisões potenciais do que a sugestão de Raymond abaixo. en.wikipedia.org/wiki/List_of_hash_functions
tryptofame
Respostas:
155
Sim, você pode usar os módulos hashlib embutidos ou a função hash embutida. Em seguida, corte os últimos oito dígitos usando operações de módulo ou operações de corte de string na forma inteira do hash:
>>> s ='she sells sea shells by the sea shore'>>># Use hashlib>>>import hashlib
>>> int(hashlib.sha1(s).hexdigest(),16)%(10**8)58097614L>>># Use hash()>>> abs(hash(s))%(10**8)82148974
anúncio de serviço público ... essa técnica não resulta em um valor hash exclusivo para a string; ele calcula um hash e, em seguida, transforma em um valor único não garantido
twneale
88
anúncio de serviço público ... exceto no caso especial de hashes perfeitos sobre um conjunto limitado de valores de entrada, as funções de hash não devem gerar valores únicos garantidos.
Raymond Hettinger
5
Você leu a pergunta do OP? Ele (ou ela) queria (ou precisava) 8 casas decimais. Além disso, a maneira como as tabelas de hash funcionam é fazer o hash em um pequeno espaço de pesquisa (a tabela esparsa). Você parece não saber que as funções hash desejadas são comumente usadas e não se importa com a pergunta real que foi feita.
Raymond Hettinger
17
Eu li a pergunta. Estou simplesmente observando que, no mesmo espaço de entrada do SHA-1, sua resposta é astronomicamente mais provável de produzir uma colisão do que não. Pelo menos algum grau de exclusividade é implicitamente exigido pela pergunta, mas sua resposta é uma função hash com o mesmo espírito de uma que simplesmente retorna 12345678 para cada entrada. Consegui gerar experimentalmente uma colisão com apenas 1000 entradas usando esse método. Para preservar a mesma probabilidade de colisão do SHA-1, você teria que mapear SHA-1 não truncados para inteiros de 8 dígitos. Eu acho que é digno de um PSA
twneale
20
Cuidado, hash (s) não tem garantia de dar os mesmos resultados em todas as plataformas e execuções.
Sr. Napik
94
A resposta de Raymond é ótima para python2 (embora você não precise do abs () nem dos parênteses em torno de 10 ** 8). No entanto, para python3, existem ressalvas importantes. Primeiro, você precisa se certificar de que está passando uma string codificada. Hoje em dia, na maioria das circunstâncias, provavelmente também é melhor fugir do sha-1 e usar algo como o sha-256. Portanto, a abordagem hashlib seria:
>>>import hashlib
>>> s ='your string'>>> int(hashlib.sha256(s.encode('utf-8')).hexdigest(),16)%10**880262417
Se você quiser usar a função hash (), a ressalva importante é que, ao contrário do Python 2.x, no Python 3.x, o resultado de hash () só será consistente dentro de um processo, não entre invocações de python. Veja aqui:
Deve-se notar que esta resposta tem uma advertência muito importante desde o Python 3.3, para proteger contra tar-pitting o Python 3.3 e superior, use uma semente de hash aleatória na inicialização.
Wolph
Se os dígitos não forem seu requisito principal, você também pode usar, mas hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]ainda assim haverá colisões
lony
Eles deveriam colocar isso na caixa!
Tomasz
3
Apenas para completar a resposta JJC, no python 3.5.3 o comportamento está correto se você usar hashlib desta forma:
Estou compartilhando nossa implementação nodejs da solução implementada por @Raymond Hettinger.
var crypto = require('crypto');
var s ='she sells sea shells by the sea shore';
console.log(BigInt('0x'+ crypto.createHash('sha1').update(s).digest('hex'))%(10n**8n));
Você está compartilhando uma solução nodejs em uma pergunta sobre python?
Harabeck
Sim, quando estávamos construindo o sistema - o back-end processou isso usando python enquanto o front-end usava node.js. Necessário para garantir que ambos funcionem perfeitamente.
Respostas:
Sim, você pode usar os módulos hashlib embutidos ou a função hash embutida. Em seguida, corte os últimos oito dígitos usando operações de módulo ou operações de corte de string na forma inteira do hash:
fonte
A resposta de Raymond é ótima para python2 (embora você não precise do abs () nem dos parênteses em torno de 10 ** 8). No entanto, para python3, existem ressalvas importantes. Primeiro, você precisa se certificar de que está passando uma string codificada. Hoje em dia, na maioria das circunstâncias, provavelmente também é melhor fugir do sha-1 e usar algo como o sha-256. Portanto, a abordagem hashlib seria:
Se você quiser usar a função hash (), a ressalva importante é que, ao contrário do Python 2.x, no Python 3.x, o resultado de hash () só será consistente dentro de um processo, não entre invocações de python. Veja aqui:
Isso significa que a solução baseada em hash () sugerida, que pode ser encurtada para apenas:
hash(s) % 10**8
retornará apenas o mesmo valor em uma determinada execução de script:
Portanto, dependendo se isso é importante no seu aplicativo (foi no meu), você provavelmente vai querer manter a abordagem baseada em hashlib.
fonte
hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]
ainda assim haverá colisõesApenas para completar a resposta JJC, no python 3.5.3 o comportamento está correto se você usar hashlib desta forma:
fonte
Estou compartilhando nossa implementação nodejs da solução implementada por @Raymond Hettinger.
fonte