2014-08-28 18 views
9

Mam dwie listy słowników i chciałbym znaleźć różnicę między nimi (tj. To, co istnieje na pierwszej liście, ale nie na drugiej, i to, co istnieje na drugiej liście, ale nie na pierwszej liście).Jak znaleźć różnicę między dwiema listami słowników?

Kwestia jest taka, że ​​jest to lista słowników

a = [{'a': '1'}, {'c': '2'}] 
b = [{'a': '1'}, {'b': '2'}] 

set(a) - set(b) 

Rezultatów

TypeError: unhashable type: 'dict' 

pożądany rezultat:

{'c': '2'} 

Jak to osiągnąć?

+1

Czy Twoje słowniki są naprawdę tylko pojedynczymi przedmiotami? jeśli tak, czy nie ma sensu tworzenie listy w jednym słowniku? – cmd

+0

nie, są to wielokrotne przedmioty (najprawdopodobniej około 15), a to byłaby lista około 3000 do 1000 rekordów na każdej liście. – Chris

+0

Możesz sprawdzić pożądany wynik. Zgodnie z twoją definicją szukasz [różnicy symetrycznej] (http://en.wikipedia.org/wiki/Symmetric_difference) –

Odpowiedz

11

Można użyć operatora in aby sprawdzić, czy znajduje się na liście

a = [{'a': '1'}, {'c': '2'}] 
b = [{'a': '1'}, {'b': '2'}] 

>>> {'a':'1'} in a 
True 
>>> {'a':'1'} in b 
True 

>>> [i for i in a if i not in b] 
[{'c': '2'}] 
0

Można również filter z lambda:

Jeśli chcesz różnych elementów w każdym liście:

print filter(lambda x: x not in b,a) + filter(lambda x: x not in a,b) 

[{'c': '2'}, {'b': '2'}] 

Lub po prostu filter(lambda x: x not in b,a), aby uzyskać elementy w a, ale nie w b Jeśli nie chcesz utworzyć pełną listę dicts w pamięci można użyć itertools.ifilter

from itertools import ifilter 

diff = ifilter(lambda x: x not in b,a) 

Następnie wystarczy iteracyjne nad Diff:

for uniq in diff: 
    print uniq 
3

Chciałbym zobaczyć różnicę między nimi (np co istnieje w pierwszym liście, ale nie drugi, a to, co istnieje w drugim liście, ale nie pierwszą listę)

Według twojej definicji Szukasz Symmetric difference:

>>> import itertools 

>>> a = [{'a': '1'}, {'c': '2'}] 
>>> b = [{'a': '1'}, {'b': '2'}] 
>>> intersec = [item for item in a if item in b] 
>>> sym_diff = [item for item in itertools.chain(a,b) if item not in intersec] 

>>> intersec 
[{'a': '1'}] 
>>> sym_diff 
[{'c': '2'}, {'b': '2'} 

Alternatywnie (korzystając z plain difference, jak podano w twoim przykładzie):

>>> a_minus_b = [item for item in a if item not in b] 
>>> b_minus_a = [item for item in b if item not in a] 
>>> sym_diff = list(itertools.chain(a_minus_b,b_minus_a)) 

>>> a_minus_b 
[{'c': '2'}] 
>>> b_minus_a 
[{'b': '2'}] 
>>> sym_diff 
[{'c': '2'}, {'b': '2'}] 
+0

To było odniesienie w jednej z odpowiedzi, ale uważam, że jest to dokładnie to, co OP chciał tutaj .. .so +1. Jedno pytanie, czy nie można użyć operatora '+' do połączenia 'a_minis_b' i' b_minus_a' do 'sym_diff' zamiast użycia' itertools.chain'? –

+1

@ KhalilAmmour- خليلعمور Tak, możesz. Ale używając 'itertools.chain()' nie musisz budować wynikowej listy w pamięci przed użyciem. Szczególnie ważne w przypadku "dużych" list. Aby być nieco bardziej zgodnym z tym, powinienem jednak użyć generatora zamiast zrozumienia listy tutaj: 'a_minus_b = (element dla pozycji w przypadku jeśli nie w b)'.Byłoby to jednak trudniejsze w tym przykładowym kodzie, ponieważ generator zużywa przedmioty podczas ich używania. –

+0

Ahah ... Rozumiem ... więc to było dla optymizacji pamięci, czy możesz pokazać mi przykład z generatorem, może to być przez edytowanie odpowiedzi, jeśli chcesz? –