2010-02-12 39 views
15

tôi có một danh sách (nhãn, đếm) tuples như thế này:Nhóm Python danh sách tuple

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

Từ mà tôi muốn tổng hợp tất cả các giá trị có cùng nhãn (giống nhãn luôn liền kề) và trả về một danh sách trong cùng một trật tự label:

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

tôi biết tôi có thể giải quyết nó với một cái gì đó như:

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 

Nhưng có một mo tái Pythonic/thanh lịch/hiệu quả cách để làm điều này?

Trả lời

23

itertools.groupby có thể làm những gì bạn muốn:

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

Tôi thích sử dụng 'operator.itemgetter' thay cho' lambda'. – jathanism

+1

Điều này yêu cầu danh sách phải được sắp xếp trên khóa đầu tiên. Nếu nó chưa được sắp xếp, thì cách tiếp cận defaultdict từ ghostdog74 là một giải pháp tốt hơn nhiều. –

5

sử dụng itertools và danh sách comprehensions

import itertools 

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

Edit: như gnibbler chỉ ra: nếu l không phải là đã được sắp xếp thay thế nó với sorted(l).

+4

để sử dụng nhóm trước tiên bạn phải đảm bảo rằng chuỗi được nhóm trước (tất cả 'nho' liền kề, v.v.). một cách để làm điều đó là sắp xếp trình tự đầu tiên –

+0

OP nói rằng các nhãn đã được nhóm lại. –

+0

@Thomas Wouters, vâng bạn đúng ("cùng nhãn luôn liền kề") –

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]) 

đầu ra

$ ./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

Hoặc một câu trả lời đơn giản dễ đọc hơn (không 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

phiên bản của tôi mà không có itertools
[(k, sum([y for (x,y) in l if x == k])) for k in dict(l).keys()]

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