2010-07-29 80 views
6

Tôi có danh sách từ điển rất dài với chỉ số chuỗi và giá trị số nguyên. Rất nhiều các phím đều giống nhau trên các bộ từ điển, mặc dù không phải tất cả. Tôi muốn tạo một từ điển trong đó các khóa là sự kết hợp của các khóa trong các từ điển riêng biệt và các giá trị là tổng của tất cả các giá trị tương ứng với khóa đó trong mỗi từ điển. (Ví dụ: giá trị cho khóa 'táo' trong từ điển kết hợp sẽ là tổng giá trị của 'táo' trong từ điển đầu tiên cộng với tổng giá trị của 'táo' trong giây thứ hai, v.v.)Thêm các phần tử vào danh sách từ điển

Tôi có những điều sau đây, nhưng khá cồng kềnh và mất độ tuổi để thực thi. Có cách nào đơn giản hơn để đạt được kết quả tương tự không?

comb_dict = {} 
for dictionary in list_dictionaries: 
    for key in dictionary: 
     comb_dict.setdefault(key, 0) 
     comb_dict[key] += dictionary[key] 
return comb_dict 

Trả lời

9

Dưới đây là một số tiêu chí vi mô đề xuất f2 (xem bên dưới) có thể là một cải tiến. f2 sử dụng iteritems cho phép bạn tránh được một tra cứu dict thêm trong vòng lặp bên trong:

import collections 
import string 
import random 

def random_dict(): 
    n=random.randint(1,26) 
    keys=list(string.letters) 
    random.shuffle(keys) 
    keys=keys[:n] 
    values=[random.randint(1,100) for _ in range(n)]  
    return dict(zip(keys,values)) 

list_dictionaries=[random_dict() for x in xrange(100)] 

def f1(list_dictionaries): 
    comb_dict = {} 
    for dictionary in list_dictionaries: 
     for key in dictionary: 
      comb_dict.setdefault(key, 0) 
      comb_dict[key] += dictionary[key] 
    return comb_dict 

def f2(list_dictionaries):  
    comb_dict = collections.defaultdict(int) 
    for dictionary in list_dictionaries: 
     for key,value in dictionary.iteritems(): 
      comb_dict[key] += value 
    return comb_dict 

def union(dict_list): 
    all_keys = set() 
    for d in dict_list: 
     for k in d: 
      all_keys.add(k) 
    for key in all_keys: 
     yield key, sum(d.get(key,0) for d in dict_list) 

def f3(list_dictionaries): 
    return dict(union(list_dictionaries)) 

Dưới đây là kết quả:

% python -mtimeit -s"import test" "test.f1(test.list_dictionaries)" 
1000 loops, best of 3: 776 usec per loop 
% python -mtimeit -s"import test" "test.f2(test.list_dictionaries)" 
1000 loops, best of 3: 432 usec per loop  
% python -mtimeit -s"import test" "test.f3(test.list_dictionaries)" 
100 loops, best of 3: 2.19 msec per loop 
+0

Cảm ơn! f2() thực sự cắt giảm khoảng 80% thời gian cho ứng dụng cụ thể của tôi. YRMV, rõ ràng. – chimeracoder

1

Điều này cũng có thể nhanh, nhưng nó thực sự phụ thuộc vào dữ liệu của bạn. Nó tránh được tất cả các dicts thay đổi hoặc danh sách thêm - chỉ là một tập hợp của tất cả các phím và rất nhiều lần đọc :-)

from itertools import chain 

def union(dict_list): 
    all_keys = set(chain.from_iterable(dict_list)) 
    for key in all_keys: 
     yield key, sum(d.get(key,0) for d in dict_list) 

combined = dict(union(dict_list)) 
+0

Mặc dù đây sử dụng các chức năng phức tạp hơn, tôi không thể tưởng tượng rằng điều này sẽ nhanh hơn (nhưng tôi có thể sai). Trong mã của OP, danh sách từ điển chỉ được duyệt qua một lần, vì vậy là mọi từ điển. Trong mã của bạn, mỗi từ điển được duyệt qua một lần để tạo tập hợp các khóa và sau đó danh sách các dấu gạch ngang sẽ được chuyển qua '# all_keys' lần. –

+0

Felix Kling: Vâng, tôi đã thử, khi tôi thêm một trình lặp (xem bản sửa đổi ;-) để duyệt qua chỉ khi nó bị chậm hơn. Đoán rằng thêm hasing từ đặt nó là vấn đề. –

0

Bạn có thể mất một số cảm hứng từ google map-giảm. Từ những gì tôi hiểu nó được thiết kế để giải quyết chỉ loại vấn đề này.

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