2014-08-28 13 views
9

Tôi có hai danh sách từ điển và tôi muốn tìm sự khác biệt giữa chúng (tức là những gì tồn tại trong danh sách đầu tiên nhưng không phải thứ hai, và những gì tồn tại trong danh sách thứ hai nhưng không phải là danh sách đầu tiên).Làm cách nào để tìm sự khác biệt giữa hai danh sách từ điển?

Vấn đề là nó là một danh sách các từ điển

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

set(a) - set(b) 

quả

TypeError: unhashable type: 'dict' 

mong muốn Kết quả:

{'c': '2'} 

Làm thế nào để thực hiện điều này?

+1

là từ điển của bạn thực sự chỉ là các mục duy nhất? nếu vậy, sẽ không có ý nghĩa hơn để làm cho danh sách thành một từ điển duy nhất? – cmd

+0

nope, chúng là nhiều mục (khoảng 15 mỗi khả năng nhất) và đây sẽ là danh sách khoảng 3000 đến 1000 chế độ độc tài trong mỗi danh sách – Chris

+0

Bạn có thể kiểm tra kết quả mong muốn của mình không. Theo định nghĩa của bạn, bạn đang tìm kiếm một [sự khác biệt đối xứng] (http://en.wikipedia.org/wiki/Symmetric_difference) –

Trả lời

11

Bạn có thể sử dụng toán tử in để xem nếu nó có trong danh sách

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

Bạn cũng có thể bạn filter với một lambda:

Nếu bạn muốn các mặt hàng khác nhau trong mỗi danh sách:

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

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

Hoặc chỉ filter(lambda x: x not in b,a) để lấy các phần tử trong a nhưng không ở trong b Nếu bạn không muốn tạo danh sách đầy đủ của dicts trong bộ nhớ, bạn có thể sử dụng itertools.ifilter

from itertools import ifilter 

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

Sau đó chỉ cần lặp qua diff:

for uniq in diff: 
    print uniq 
3

tôi muốn tìm sự khác biệt giữa chúng (tức là những gì tồn tại trong danh sách đầu tiên nhưng không phải là thứ hai, và những gì tồn tại trong danh sách thứ hai nhưng không phải là danh sách đầu tiên)

Theo định nghĩa của bạn, bạn đang tìm kiếm một 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'} 

Cách khác (sử dụng số plain difference như được đưa ra trong ví dụ của bạn):

>>> 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

Điều này được tham chiếu trong một trong các câu trả lời nhưng tôi tin rằng đây chính xác là những gì OP muốn ở đây .. .so +1. Một câu hỏi, bạn không thể sử dụng toán tử '+' để nối 'a_minis_b' và' b_minus_a' thành 'sym_diff' thay vì sử dụng' itertools.chain'? –

+1

@ KhalilAmmour- خليلعمور Có bạn có thể. Nhưng sử dụng 'itertools.chain()' bạn không phải xây dựng danh sách kết quả trong bộ nhớ trước khi sử dụng nó. Đặc biệt quan trọng đối với danh sách "lớn". Để có một chút phù hợp hơn với điều đó, tôi nên sử dụng một máy phát điện thay vì một danh sách hiểu ở đây: 'a_minus_b = (mục cho mục trong một mục nếu không có trong b)'.Nhưng điều này sẽ phức tạp hơn trong mã mẫu đó, vì máy phát sẽ tiêu thụ các mục khi bạn sử dụng chúng. –

+0

Ahah ... Tôi hiểu ... vì vậy là để tối ưu hóa trí nhớ, bạn có thể chỉ cho tôi một ví dụ với máy phát điện, có thể thông qua chỉnh sửa câu trả lời của bạn, nếu bạn muốn? –

Các vấn đề liên quan