Każda skończona liczba cyfr spowoduje kolizje dla wystarczająco dużej liczby elementów haszujących, dlatego nie należy ich traktować jako unikalnych kluczy - zwykle zmienia się to w problem urodzinowy.
Alex North-Keys
1
Wybrałem "CityHash", aby zahaszować ciągi do 19-cyfrowych liczb całkowitych (64-bitowych liczb całkowitych), mając nadzieję, że doprowadzi to do mniej potencjalnych kolizji niż sugestia Raymonda poniżej. en.wikipedia.org/wiki/List_of_hash_functions
tryptofame
Odpowiedzi:
159
Tak, możesz użyć wbudowanych modułów hashlib lub wbudowanej funkcji skrótu . Następnie odetnij ostatnie osiem cyfr za pomocą operacji modulo lub operacji cięcia łańcuchów na całkowitej postaci hasha:
>>> 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
ogłoszenie o usłudze publicznej ... ta technika w rzeczywistości nie daje unikalnej wartości skrótu dla ciągu; oblicza hash, a następnie łączy się z niegwarantowaną-unikalną wartością
twneale
90
ogłoszenie o usłudze publicznej ... z wyjątkiem specjalnego przypadku doskonałych skrótów na ograniczonym zestawie wartości wejściowych, funkcje skrótu nie powinny generować gwarantowanych unikalnych wartości.
Raymond Hettinger
5
Czy przeczytałeś pytanie OP? Chciał (lub potrzebował) 8 miejsc po przecinku. Ponadto sposób działania tabel skrótów polega na haszowaniu w małej przestrzeni wyszukiwania (rzadka tabela). Wydaje się, że nie wiesz, że funkcje skrótu Want są powszechnie używane i nie przejmujesz się tym, jakie zostało zadane pytanie.
Raymond Hettinger
18
Przeczytałem pytanie. Po prostu obserwuję, że w tej samej przestrzeni wejściowej co SHA-1 twoja odpowiedź jest astronomicznie bardziej prawdopodobne, że spowoduje zderzenie niż nie. Pytanie wymaga co najmniej pewnego stopnia niepowtarzalności, ale twoja odpowiedź jest funkcją skrótu w tym samym duchu, co funkcja, która po prostu zwraca 12345678 dla każdego wejścia. Udało mi się eksperymentalnie wygenerować kolizję z zaledwie 1000 wejściami przy użyciu tej metody. Aby zachować takie samo prawdopodobieństwo kolizji jak SHA-1, należałoby odwzorować nieobcięte SHA-1 na 8-cyfrowe liczby całkowite. Myślę, że to jest warte PSA
twneale
20
Ostrożnie, hashy nie są gwarantowane, aby dać takie same wyniki na różnych platformach i przebiegach.
Pan Napik
99
Odpowiedź Raymonda jest świetna dla pythona2 (chociaż nie potrzebujesz abs () ani parens około 10 ** 8). Jednak w przypadku python3 istnieją ważne zastrzeżenia. Najpierw musisz się upewnić, że przekazujesz zakodowany ciąg. W dzisiejszych czasach, w większości przypadków, prawdopodobnie lepiej jest unikać sha-1 i zamiast tego używać czegoś takiego jak sha-256. Zatem podejście hashlib wyglądałoby tak:
Jeśli zamiast tego chcesz użyć funkcji hash (), ważnym zastrzeżeniem jest to, że w przeciwieństwie do Pythona 2.x, w Pythonie 3.x wynik funkcji hash () będzie spójny tylko w ramach procesu, a nie w wywołaniach Pythona. Spójrz tutaj:
Tak więc, w zależności od tego, czy ma to znaczenie w Twojej aplikacji (tak było w mojej), prawdopodobnie będziesz chciał trzymać się podejścia opartego na hashlib.
Należy zauważyć, że ta odpowiedź ma bardzo ważne zastrzeżenie od czasu Pythona 3.3, aby chronić przed tar-pittingiem Python 3.3 i nowsze wersje używają losowego zarodka hash podczas uruchamiania.
Wolph
Jeśli cyfry nie są twoim głównym wymaganiem, możesz również użyć hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]czarownicy nadal będą miały kolizje
lony
Powinni umieścić to na pudełku!
Tomasz
3
Aby uzupełnić odpowiedź JJC, w pythonie 3.5.3 zachowanie jest poprawne, jeśli używasz hashlib w ten sposób:
Dzielę się naszym wdrożeniem nodejs rozwiązania zaimplementowanym przez @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));
Udostępniasz rozwiązanie nodejs w pytaniu o Pythona?
Harabeck
Tak, kiedy budowaliśmy system - backend przetwarzał to za pomocą Pythona, podczas gdy frontend używał node.js. Potrzebne, aby upewnić się, że oba działają bezproblemowo.
Odpowiedzi:
Tak, możesz użyć wbudowanych modułów hashlib lub wbudowanej funkcji skrótu . Następnie odetnij ostatnie osiem cyfr za pomocą operacji modulo lub operacji cięcia łańcuchów na całkowitej postaci hasha:
>>> 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
źródło
Odpowiedź Raymonda jest świetna dla pythona2 (chociaż nie potrzebujesz abs () ani parens około 10 ** 8). Jednak w przypadku python3 istnieją ważne zastrzeżenia. Najpierw musisz się upewnić, że przekazujesz zakodowany ciąg. W dzisiejszych czasach, w większości przypadków, prawdopodobnie lepiej jest unikać sha-1 i zamiast tego używać czegoś takiego jak sha-256. Zatem podejście hashlib wyglądałoby tak:
>>> import hashlib >>> s = 'your string' >>> int(hashlib.sha256(s.encode('utf-8')).hexdigest(), 16) % 10**8 80262417
Jeśli zamiast tego chcesz użyć funkcji hash (), ważnym zastrzeżeniem jest to, że w przeciwieństwie do Pythona 2.x, w Pythonie 3.x wynik funkcji hash () będzie spójny tylko w ramach procesu, a nie w wywołaniach Pythona. Spójrz tutaj:
$ python -V Python 2.7.5 $ python -c 'print(hash("foo"))' -4177197833195190597 $ python -c 'print(hash("foo"))' -4177197833195190597 $ python3 -V Python 3.4.2 $ python3 -c 'print(hash("foo"))' 5790391865899772265 $ python3 -c 'print(hash("foo"))' -8152690834165248934
Oznacza to sugerowane rozwiązanie oparte na hash (), które można skrócić do zaledwie:
hash(s) % 10**8
zwróci tę samą wartość tylko w ramach danego uruchomienia skryptu:
#Python 2: $ python2 -c 's="your string"; print(hash(s) % 10**8)' 52304543 $ python2 -c 's="your string"; print(hash(s) % 10**8)' 52304543 #Python 3: $ python3 -c 's="your string"; print(hash(s) % 10**8)' 12954124 $ python3 -c 's="your string"; print(hash(s) % 10**8)' 32065451
Tak więc, w zależności od tego, czy ma to znaczenie w Twojej aplikacji (tak było w mojej), prawdopodobnie będziesz chciał trzymać się podejścia opartego na hashlib.
źródło
hashlib.sha256("hello world".encode('utf-8')).hexdigest()[:8]
czarownicy nadal będą miały kolizjeAby uzupełnić odpowiedź JJC, w pythonie 3.5.3 zachowanie jest poprawne, jeśli używasz hashlib w ten sposób:
$ python3 -c ' import hashlib hash_object = hashlib.sha256(b"Caroline") hex_dig = hash_object.hexdigest() print(hex_dig) ' 739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded $ python3 -c ' import hashlib hash_object = hashlib.sha256(b"Caroline") hex_dig = hash_object.hexdigest() print(hex_dig) ' 739061d73d65dcdeb755aa28da4fea16a02b9c99b4c2735f2ebfa016f3e7fded $ python3 -V Python 3.5.3
źródło
Dzielę się naszym wdrożeniem nodejs rozwiązania zaimplementowanym przez @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));
źródło