2009-06-23 51 views
28

thể trùng lặp:
python dict.add_by_value(dict_2) ?"Thêm" Từ điển bằng Python?

đầu vào của tôi là hai bộ từ điển có phím chuỗi và giá trị số nguyên. Tôi muốn thêm hai từ điển để kết quả có tất cả các khóa của các bộ từ điển đầu vào, và các giá trị là tổng của các giá trị từ điển đầu vào.

Để rõ ràng, nếu khóa chỉ xuất hiện trong một trong các đầu vào, khóa/giá trị đó sẽ xuất hiện trong kết quả, trong khi nếu khóa xuất hiện trong cả hai từ điển thì tổng giá trị sẽ xuất hiện trong kết quả.

Ví dụ, nói đầu vào của tôi là:

a = dict() 
a['cat'] = 1 
a['fish'] = 10 
a['aardvark'] = 1000 

b = dict() 
b['cat'] = 2 
b['dog'] = 200 
b['aardvark'] = 2000 

Tôi muốn kết quả là:

{'cat': 3, 'fish': 10, 'dog': 200, 'aardvark': 3000} 

Biết Python thì phải có một lớp lót để thực hiện điều này (nó doesn 't thực sự phải là một dòng ...). Có suy nghĩ gì không?

+1

Câu hỏi đặt ra là trùng lặp, câu trả lời là không ;-) – Juergen

+0

@msanders: Trên thực tế nó không phải là một trùng lặp, những câu hỏi mà bạn đang đề cập đến yêu cầu tất cả các từ điển để có chính xác các phím cùng –

Trả lời

50

Làm thế nào về điều đó:

dict([ (n, a.get(n, 0)+b.get(n, 0)) for n in set(a)|set(b) ]) 

Hoặc mà không cần tạo một danh sách trung gian (máy phát điện là đủ):

dict((n, a.get(n, 0)+b.get(n, 0)) for n in set(a)|set(b)) 

bài Scriptum:

Là một nhà bình luận đề cập một cách chính xác, có một cách để thực hiện điều đó dễ dàng hơn với các mới (từ Py2.7) lớp collections.Counter. Càng nhiều Tôi nhớ, phiên bản này là không có sẵn khi tôi đã viết câu trả lời:

from collections import Counter 
dict(Counter(a)+Counter(b)) 
+1

+1 tốt đẹp, mặc dù dấu ngoặc vuông không cần thiết vì dict() sẽ nhận một máy phát điện – cobbal

+0

Thats đúng! Chỉ là thói quen của tôi. Tôi đã thấy nó sau đó. – Juergen

+2

+1: đẹp một lớp lót. Tuy nhiên, tôi muốn đặt (a) .union (b), để không tạo ra một tập hợp trung gian [set (b)]. – EOL

15

kết quả trong a:

for elem in b: 
    a[elem] = a.get(elem, 0) + b[elem] 

kết quả trong c:

c = dict(a) 
for elem in b: 
    c[elem] = a.get(elem, 0) + b[elem] 
+1

Đây là hai dòng btw :) – Aamir

+6

Không phải là một lớp lót, nhưng dễ đọc nhất. +1 –

+0

Trong trường hợp này, hai dòng là tốt hơn một dòng. –

15

Không có trong một dòng, nhưng ...

import itertools 
import collections 
a = dict() 
a['cat'] = 1 
a['fish'] = 10 
a['aardvark'] = 1000 
b = dict() 
b['cat'] = 2 
b['dog'] = 200 
b['aardvark'] = 2000 
c = collections.defaultdict(int) 
for k, v in itertools.chain(a.iteritems(), b.iteritems()): 
    c[k] += v 

Bạn có thể dễ dàng mở rộng nó đến một số lượng lớn các từ điển .

+0

itertools.chain là một giải pháp tốt, khi tốc độ tối đa là cần thiết, vì trong giải pháp của tôi một tập hợp tạm thời được tạo ra. Tôi cho rằng, dây chuyền nhanh hơn cho những người dicts lớn. – Juergen

+0

Vâng, tôi đã không sử dụng nó cho tốc độ ở đây. Tôi không cần kiểm tra xem có yếu tố nào bị thiếu trong b và ngược lại hay không. –

4

Một lớp lót (như yêu cầu sắp xếp): lấy danh sách khóa, thêm chúng, loại bỏ trùng lặp, lặp lại kết quả với danh sách hiểu, cặp trả về (khóa, giá trị) cho tổng nếu khóa nằm trong cả hai mã, hoặc chỉ các giá trị riêng lẻ nếu không. Bọc trong dict.

>>> dict([(x,a[x]+b[x]) if (x in a and x in b) else (x,a[x]) if (x in a) else (x,b[x]) for x in set(a.keys()+b.keys())]) 
{'aardvark': 3000, 'fish': 10, 'dog': 200, 'cat': 3} 
Các vấn đề liên quan