2015-12-15 6 views
11

mam dwa słowniki, które mają następującą strukturę:Python: Znajdź różnicę między dwoma słowników zawierających wykazy

a = {'joe': [24,32,422], 'bob': [1,42,32,24], 'jack':[0,3,222]} 
b = {'joe': [24], 'bob': [1,42,32]} 

chciałbym odzyskać różnicę między tymi dwoma słownikami, które w tym przypadku wynik:

{'joe': [32,422], 'bob': [24], 'jack':[0,3,222]} 

Wiem, że mogłem to zrobić z nieuporządkowaną pętlą, ale chciałbym wiedzieć, jak mogę to osiągnąć w czysty, pytonowy sposób?

Próbowałem: a.items() - b.items()

ale pojawia się następujący błąd: unsupported operand type(s) for -: 'dict_values' and 'dict_values'

dzięki za pomoc

+1

Chciałbym podkreślić, że odpowiedzi w użyciu zestawów które są rzucane z powrotem na listy, niszczą kolejność list (jeśli kolejność nie zostanie zmieniona dla konkretnego przykładu, to zbieg okoliczności). Ponieważ twoje specyfikacje nie mówią, że kolejność list jest nieistotna, myślę, że należy to odnotować. – timgeb

Odpowiedz

11

zakładając, że nie będzie nie twórz żadnych duplikatów na żadnej z twoich list, możesz robić, co chcesz, przy pomocy set s, ale nie z listami:

>>> a = {'joe': [24,32,422], 'bob': [1,42,32,24], 'jack':[0,3,222]} 
>>> b = {'joe': [24], 'bob': [1,42,32]} 
>>> {key: list(set(a[key])- set(b.get(key,[]))) for key in a} 
{'joe': [32, 422], 'bob': [24], 'jack': [0, 3, 222]} 

Note dwie rzeczy:

  • przekonwertować zestaw z powrotem do listy kiedy ustawić ją jako wartość
  • używam b.get zamiast b[key] obsłużyć jeśli klucz nie istnieje w b, ale nie w a

EDIT - za pomocą pętli:

zdałem sobie sprawę, że rozumienie nie może być tak, że wymowne więc jest to odpowiednik kawałek kodu za pomocą pętli for:

>>> c = {} 
>>> for key in a: 
    c[key] = list(set(a[key]) - set(b.get(key,[]))) 


>>> c 
{'joe': [32, 422], 'bob': [24], 'jack': [0, 3, 222]} 

EDIT - stracić drugiego zestawu:

Jak Padraic Cunningham mowa w komentarze (jak to często robi, błogosław jego duszę), można skorzystać z set.difference uniknąć wyraźnie odlewania swoją drugą listę do zestawu:

>>> c = {} 
>>> for key in a: 
    c[key] = list(set(a[key]).difference(b.get(key,[]))) 


>>> c 
{'joe': [32, 422], 'bob': [24], 'jack': [0, 3, 222]} 

lub z listowego:

>>> {key: list(set(a[key]).difference(b.get(key,[]))) for key in a} 
{'joe': [32, 422], 'bob': [24], 'jack': [0, 3, 222]} 

lub jeśli chcesz traktować set.difference jako metoda klasy zamiast metody instancji:

>>> {key: list(set.difference(set(a[key]),b.get(key,[]))) for key in a} 
{'joe': [32, 422], 'bob': [24], 'jack': [0, 3, 222]} 

Choć uważam to nieco tad niezgrabne, a ja nie lubię go tak samo.

+0

podobnie jak użycie ze zrozumieniem ..... –

+0

Idealny! Świetna odpowiedź i jeszcze raz dziękuję za wyjaśnienie. – Ryan

+0

Nie musisz wywoływać zestawu dwa razy, możesz użyć 'set.difference' –

7

Musisz użyć zestawach:

diff = {} 
for key in a: 
    diff[key] = list(set(a[key]) - set(b.get(key, []))) 
print diff 
4

Innym sposobem jest użycie wbudowanej metody filter:

>>> a = {'joe': [24,32,422], 'bob': [1,42,32,24], 'jack':[0,3,222]} 
>>> b = {'joe': [24], 'bob': [1,42,32]} 
>>> {key:filter(lambda s: s not in b.get(key,[]), a[key]) for key in a} 
{'bob': [24], 'joe': [32, 422], 'jack': [0, 3, 222]} 

zgodnie Padraic Cunningham Komentarze:

W Pythonie 3, filter Zwraca generator, więc trzeba przekonwertować go na wykaz ten sposób:

{key:list(filter(lambda s: s not in b.get(key,[]), a[key])) for key in a}

+1

Potrzebujesz 'lista (filtr ...' dla każdego używającego python3 –

+0

Tak ... ale OP wspomniał, że jest 2.7 –

+2

Tak, ale inni mogą zobaczyć odpowiedź;) –