2013-04-18 10 views
9

Jaki jest najlepszy sposób wygenerowania unikalnego klucza dla zawartości słownika. Moim zamiarem jest przechowywanie każdego słownika w magazynie dokumentów wraz z unikalnym identyfikatorem lub hash, tak aby nie musiałem ładować całego słownika ze sklepu, aby sprawdzić, czy istnieje już on, czy nie. Słowniki z tymi samymi kluczami i wartościami powinny generować ten sam identyfikator lub skrót.Jak utworzyć unikalny klucz dla słownika w języku Python

Mam następujący kod:

import hashlib 

a={'name':'Danish', 'age':107} 
b={'age':107, 'name':'Danish'} 

print str(a) 
print hashlib.sha1(str(a)).hexdigest() 
print hashlib.sha1(str(b)).hexdigest() 

ostatnich dwóch instrukcji print generuje ten sam ciąg. Czy to jest dobra implementacja? czy są jakieś pułapki z tym podejściem? Czy jest lepszy sposób to zrobić?

Aktualizacja

Łączenie propozycje z poniższych odpowiedzi, co następuje może być dobre wykonanie

import hashlib 

a={'name':'Danish', 'age':107} 
b={'age':107, 'name':'Danish'} 


def get_id_for_dict(dict): 
    unique_str = ''.join(["'%s':'%s';"%(key, val) for (key, val) in sorted(dict.items())]) 
    return hashlib.sha1(unique_str).hexdigest() 

print get_id_for_dict(a) 
print get_id_for_dict(b) 
+0

Implementacja w aktualizacji jest bardzo źle: spróbuj tego: 'get_id_for_dict ({ 'foo':” bar '}) 'lub' get_id_for_dict ({' fo ':' obar '}) 'lub' get_id_for_dict ({' f ':' o ',' o ':' bar '}) '. Wszystkie zwracają '8843d7f92416211de9ebb963ff4ce28125932878'. Lepiej użyj 'unique_str = join (['% s% s'% (hashlib.sha1 (key), hashlib.sha1 (val)) dla (key, val) w posortowanym (dict.items())])' – Tometzky

+0

@ Tometzky Dzięki za wskazanie mojego błędu. Próbowałem Twojej sugestii, ale nie udało się, jeśli klucze lub wartości nie są typu ciąg. Zamiast tego, właśnie zmieniłem format ciągu, aby zawrzeć klucz i wartość w cudzysłowach i umieścić między nimi znak dwukropka. – Danish

+0

Nadal nie jest dobrze, jeśli w kluczu lub wartości mogą znajdować się '' ',': 'i'; '. Użyj 'unique_str = join (['% s% s'% (hashlib.sha1 (str (key)), hashlib.sha1 (str (val))) dla (key, val) w posortowaniu (dict.items()) ]) ' – Tometzky

Odpowiedz

3

Możliwym rozwiązaniem byłoby przy użyciu zserializowaną reprezentację na liście, która zachowuje porządek. Nie jestem pewien, czy domyślna lista do mechanizmu ciągów nakłada jakiekolwiek zlecenia, ale nie zdziwiłbym się, gdyby był on zależny od tłumacza. Zasadniczo zbudowałem coś podobnego do urlencode, które wcześniej sortuje klucze.

Nie sądzę, że metoda zawiodłaby, ale wolałbym grać z przewidywalnymi rzeczami i unikać nieudokumentowanych i/lub nieprzewidywalnych zachowań. To prawda, że ​​pomimo "nieuporządkowania", słowniki kończą się zamówieniem, które może być nawet spójne, ale chodzi o to, że nie powinieneś brać tego za pewnik.

+0

Przepraszam, nie byłem jasny. Moim zamiarem jest, aby słowniki z tymi samymi kluczami i wartościami generowały ten sam identyfikator lub hash – Danish

+0

-1. Z mojego odczytania pytania unikalny identyfikator powinien być oparty na zawartości słownika. –

+0

@StevenRumbalski Pedro odpowiedział, zanim dodałem moje wyjaśnienie w pytaniu. – Danish

7

Nie - you can't rely on particular order of elements when converting dictionary to a string.

Można jednak przekonwertować go do posortowanej listy (klucz, wartość) krotek, przekonwertować go na ciąg i obliczyć wartość mieszania tak:

a_sorted_list = [(key, a[key]) for key in sorted(a.keys())] 
print hashlib.sha1(str(a_sorted_list)).hexdigest() 

To nie jest idiotoodporny jako formatowania z listy przekonwertowanej na ciąg lub formatowanie krotki może się zmienić w przyszłości w większej wersji pythona, kolejność sortowania zależy od ustawień regionalnych itp., ale myślę, że może być wystarczająco dobra.

+5

Lepiej byłoby użyć "posortowane (a.items())", a następnie można zwinąć to do jednej liniowej bez utraty czytelności. –

23

Wolę szeregowania dict jako JSON i mieszania, że:

import hashlib 
import json 

a={'name':'Danish', 'age':107} 
b={'age':107, 'name':'Danish'} 

print hashlib.sha1(json.dumps(a, sort_keys=True)).hexdigest() 
print hashlib.sha1(json.dumps(b, sort_keys=True)).hexdigest() 

Powroty:

71083588011445f0e65e11c80524640668d3797d 
71083588011445f0e65e11c80524640668d3797d 
+0

Dzięki! Jest to naprawdę eleganckie rozwiązanie, które dba o rozróżnienie między '{'b':" ar "," f ":" oo "}' i '{'b':" ar "," f ":" oo " } 'również. – Danish

Powiązane problemy