2009-06-10 37 views
7

Tôi có một danh sách các từ điển, ví dụ:Làm thế nào để tạo ra một dict Python đơn lẻ từ một danh sách các dicts bằng cách tổng hợp các giá trị với các phím chung?

dictList = [ 
    {'a':3, 'b':9, 'c':4}, 
    {'a':9, 'b':24, 'c':99}, 
    {'a':10, 'b':23, 'c':88} 
] 

Tất cả các từ điển có các phím cùng một ví dụ a, b, c. Tôi muốn tạo một từ điển duy nhất có cùng các khóa, trong đó các giá trị là tổng của các giá trị có cùng các khóa từ tất cả các từ điển trong danh sách gốc.

Vì vậy, cho ví dụ trên, sản lượng nên là:

{'a':22, 'b':56, 'c':191} 

Điều gì sẽ là cách hiệu quả nhất để làm điều này? Tôi hiện đang có:

result = {} 
for myDict in dictList: 
    for k in myDict: 
     result[k] = result.setdefault(k, 0) + myDict[k] 

Trả lời

18

Nếu tất cả dicts có tất cả các phím, bạn có thể làm điều này như:

>>> dict((key, sum(d[key] for d in dictList)) for key in dictList[0]) 
{'a': 22, 'b': 56, 'c': 191} 

[Chỉnh sửa] Nếu tốc độ là một ưu tiên lớn, bạn cũng có thể cạo ~ 20 % (mặc dù ở mức chi phí của một số khả năng đọc) với những điều sau đây thay thế:

import operator, itertools 
dict((key, sum(itertools.imap(operator.itemgetter(key), dictList))) 
     for key in dictList[0]) 

Tốc độ phụ thuộc vào kích thước của dict. Tôi có được timings sau cho bản gốc danh sách 3 mục, và cho các kích cỡ khác nhau khác nhau (tạo ra bởi mutliplying danh sách ban đầu 10, 100 hay 1000 vv):

List Size Original  dict+generator  imap+itemgetter 
     3  0.054   0.090    0.097 
    30  0.473   0.255    0.236 
    300  4.668   1.884    1.529 
    3000  46.668   17.975    14.499 

(Tất cả thời gian cho 10.000 chạy)

Vì vậy, nó hơi chậm hơn cho chỉ 3, nhưng 2-3 lần nhanh cho các danh sách lớn hơn.

+3

+1 và nếu họ không có tất cả các phím: dict ((key, sum (d.get (key, 0) cho d trong dictList)) cho khóa trong dictList [0])) –

+0

@Nadia: cả câu trả lời của Brian và nhận xét của bạn cho cùng một mã – uolot

+1

@paffnucy: không, chúng không/ – SilentGhost

7

Hãy thử điều này.

from collections import defaultdict 
result = defaultdict(int) 
for myDict in dictList: 
    for k in myDict: 
     result[k] += myDict[k] 
+0

+1 để tìm hiểu cho tôi một mẹo khác. – NicDumZ

0

Tôi không chắc chắn làm thế nào nó liên quan đến câu trả lời khác tốc độ khôn ngoan, nhưng luôn luôn có

from collections import Counter 
result = sum(map(Counter,dictList),Counter()) 

Counter là một lớp con của dict và nó có thể được sử dụng thay cho dict trong hầu hết các nơi. Nếu cần thiết, bạn chỉ có thể chuyển đổi nó trở thành một dict

result = dict(result) 
Các vấn đề liên quan