2010-02-12 71 views
15

我的列表(標籤,計數)元組是這樣的:分組Python的元組列表

[('grape', 100), ('grape', 3), ('apple', 15), ('apple', 10), ('apple', 4), ('banana', 3)] 

,從我要總結具有相同標籤的所有的值(同一標籤總是相鄰),並返回一個列表在相同的標籤順序:

[('grape', 103), ('apple', 29), ('banana', 3)] 

我知道我可以用類似解決它:

def group(l): 
    result = [] 
    if l: 
     this_label = l[0][0] 
     this_count = 0 
     for label, count in l: 
      if label != this_label: 
       result.append((this_label, this_count)) 
       this_label = label 
       this_count = 0 
      this_count += count 
     result.append((this_label, this_count)) 
    return result 

但有一個MO重新Pythonic /優雅/有效的方式來做到這一點?

回答

23

itertools.groupby可以做你想做什麼:

import itertools 
import operator 

L = [('grape', 100), ('grape', 3), ('apple', 15), ('apple', 10), 
    ('apple', 4), ('banana', 3)] 

def accumulate(l): 
    it = itertools.groupby(l, operator.itemgetter(0)) 
    for key, subiter in it: 
     yield key, sum(item[1] for item in subiter) 

>>> print list(accumulate(L)) 
[('grape', 103), ('apple', 29), ('banana', 3)] 
>>> 
+4

我喜歡用'operator.itemgetter'來代替'lambda'。 – jathanism 2010-02-12 01:48:37

+1

這要求列表按第一個鍵排序。如果它尚未排序,那麼ghostdog74的defaultdict方法是更好的解決方案。 – 2016-10-10 21:05:35

5

使用itertools和list解析

import itertools 

[(key, sum(num for _, num in value)) 
    for key, value in itertools.groupby(l, lambda x: x[0])] 

編輯:爲gnibbler指出:如果l是不是已經排序與sorted(l)更換。

+4

使用GROUPBY,您必須首先確保序列pregrouped(所有的「葡萄」相鄰,等等)。一種方法是首先對序列進行排序 – 2010-02-12 01:30:12

+0

OP聲稱標籤已經分組。 – 2010-02-12 01:31:59

+0

@Thomas Wouters,是的,你是正確的(「相同的標籤總是相鄰的」) – 2010-02-12 01:40:12

3
import collections 
d=collections.defaultdict(int) 
a=[] 
alist=[('grape', 100), ('banana', 3), ('apple', 10), ('apple', 4), ('grape', 3), ('apple', 15)] 
for fruit,number in alist: 
    if not fruit in a: a.append(fruit) 
    d[fruit]+=number 
for f in a: 
    print (f,d[f]) 

輸出

$ ./python.py 
('grape', 103) 
('banana', 3) 
('apple', 29) 
3
>>> from itertools import groupby 
>>> from operator import itemgetter 
>>> L=[('grape', 100), ('grape', 3), ('apple', 15), ('apple', 10), ('apple', 4), ('banana', 3)] 
>>> [(x,sum(map(itemgetter(1),y))) for x,y in groupby(L, itemgetter(0))] 
[('grape', 103), ('apple', 29), ('banana', 3)] 
0

或者更簡單更可讀的答案(不itertools):

pairs = [('foo',1),('bar',2),('foo',2),('bar',3)] 

def sum_pairs(pairs): 
    sums = {} 
    for pair in pairs: 
    sums.setdefault(pair[0], 0) 
    sums[pair[0]] += pair[1] 
    return sums.items() 

print sum_pairs(pairs) 
1

我的版本不itertools
[(k, sum([y for (x,y) in l if x == k])) for k in dict(l).keys()]