2013-04-21 39 views
1

讓說我有一個列表:Python的 - 總結詞典列表與條件

l = [{"num1":3, "num2":8, "num3":5, "type":"A"}, {"num1":2, "num2":5, "num3":5, "type":"B"}, {"num1":5, "num2":2, "num3":1, "type":"A"}, {"num1":4, "num2":4, "num3":9, "type":"B"} 

,我想創建2點字典: SUMA:

{"num1":8, "num2":10, "num3":6} 

sumB:

{"num1":6, "num2":9, "num3":14} 

我想盡可能使它簡單易讀。 我設法用一個可怕的方式使用太多的變量...

謝謝!

+0

在那裏總是4在名單上的字典,並且總是隻有3位nubmers他們每個人? – 2013-04-21 14:52:42

+0

「我設法使用太多變量來以可怕的方式做到這一點......」那麼爲什麼不在這裏粘貼這些代碼呢? – 2013-04-21 15:00:22

+0

@lonut Hulub - 數字總是相同的(4和3只是例子) – gilgil28 2013-04-21 15:22:58

回答

1

這可以使用一些list and dict comprehensions合理輕鬆地完成。

from operator import itemgetter 
from itertools import groupby 

l = [{"num1": 3, "num2": 8, "num3": 5, "type": "A"}, 
    {"num1": 2, "num2": 5, "num3": 5, "type": "B"}, 
    {"num1": 5, "num2": 2, "num3": 1, "type": "A"}, 
    {"num1": 4, "num2": 4, "num3": 9, "type": "B"}] 

wanted_values = {"num1", "num2", "num3"} 

type_getter = itemgetter("type") 
groups = [(group, list(items)) for group, items in 
      groupby(sorted(l, key=type_getter), type_getter)] 

print({group: {k: sum(map(itemgetter(k), items)) for k in wanted_values} 
     for group, items in groups}) 

這給了我們:

{'B': {'num2': 9, 'num3': 14, 'num1': 6}, 
'A': {'num2': 10, 'num3': 6, 'num1': 8}} 

我們按類型的值進行排序,然後將它們分成組,itertools.groupby()(這些項列出,而不是發電機,因爲我們需要對他們多次迭代)。

然後,我們使用嵌套的詞典理解來創建我們需要的數據,將項目中的值相加並將它們分配給一個組。

這是一個靈活的解決方案,可以擴展到只有兩種類型。

+0

你是否運行過這段代碼?我嘗試運行時遇到TypeError。 – 2013-04-21 14:58:30

+0

@segfolt我做了,它爲我工作,我會再次檢查。 – 2013-04-21 14:59:04

+0

@segfolt我(偶然)在2.x中運行它 - 它在3.x中似乎不起作用,讓我來解決這個問題。 – 2013-04-21 15:00:51

0

我會使用嵌套的理解。

lst = [{"num1": 3, "num2": 8, "num3": 5, "type": "A"}, 
    {"num1": 2, "num2": 5, "num3": 5, "type": "B"}, 
    {"num1": 5, "num2": 2, "num3": 1, "type": "A"}, 
    {"num1": 4, "num2": 4, "num3": 9, "type": "B"}] 

sum_by_a = {key: sum(d[key] for d in lst if d['type'] == 'A') 
    for key in ("num1", "num2", "num3")} 

,或者對於一個泛型類型,

sum_by_type = lambda t: { 
    key: sum(d[key] for d in lst if d['type'] == t) 
     for key in ("num1", "num2", "num3")} 

sum_by_b = sum_by_type(B) 
+0

看起來不錯 – gilgil28 2013-04-21 15:18:08

+0

@ gilgil28:接我!選我!沒有便宜的進口,100%本地製造! – georg 2013-04-21 15:20:31

+0

lambda?我必須首先看到什麼是... – gilgil28 2013-04-21 15:28:57

0

我會走那條路,使用Collections.Counter

from collections import Counter 
from functools import reduce 

l = [{"num1":3, "num2":8, "num3":5, "type":"A"}, 
    {"num1":2, "num2":5, "num3":5, "type":"B"}, 
    {"num1":5, "num2":2, "num3":1, "type":"A"}, 
    {"num1":4, "num2":4, "num3":9, "type":"B"}] 

def remove_keys(d, keys): 
    return {i: j for i, j in d.items() if i not in keys} 

def add_dicts(dicts): 
    return reduce(lambda a, b: a+b, map(Counter, dicts)) 

tmp = {} 
for d in l: 
    tmp[d["type"]] = tmp.get(d["type"], []) + [remove_keys(d, ["type"])] 

result = {key: add_dicts(value) for key, value in dict(tmp).items()} 

這給:

{'A': Counter({'num2': 10, 'num1': 8, 'num3': 6}), 
'B': Counter({'num3': 14, 'num2': 9, 'num1': 6})}