分组Python元组列表

hoj*_*oju 21 python grouping

我有一个(标签,计数)元组列表,如下所示:

[('grape', 100), ('grape', 3), ('apple', 15), ('apple', 10), ('apple', 4), ('banana', 3)]
Run Code Online (Sandbox Code Playgroud)

从那里我想要使用相同的标签(相同的标签始终相邻)对所有值求和,并以相同的标签顺序返回一个列表:

[('grape', 103), ('apple', 29), ('banana', 3)]
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过以下方式解决它:

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
Run Code Online (Sandbox Code Playgroud)

但是,有更多Pythonic /优雅/有效的方法吗?

Tho*_*ers 32

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)]
>>> 
Run Code Online (Sandbox Code Playgroud)

  • 这要求列表在第一个键上排序.如果它尚未排序,那么来自ghostdog74的defaultdict方法是一个更好的解决方案. (7认同)
  • 我喜欢使用`operator.itemgetter`来代替`lambda`. (5认同)

cob*_*bal 6

使用itertools和列表推导

import itertools

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

编辑:正如gnibbler所指出的:如果l尚未排序,请将其替换为sorted(l).

  • 要使用groupby,你必须首先确保序列是预先编组的(所有'葡萄'相邻等).一种方法是首先对序列进行排序 (5认同)

gho*_*g74 5

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])
Run Code Online (Sandbox Code Playgroud)

产量

$ ./python.py
('grape', 103)
('banana', 3)
('apple', 29)
Run Code Online (Sandbox Code Playgroud)


Joh*_*ooy 5

>>> 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)]
Run Code Online (Sandbox Code Playgroud)