分组 Python 元组列表

Posted

技术标签:

【中文标题】分组 Python 元组列表【英文标题】:Grouping Python tuple list 【发布时间】:2011-01-15 23:34:51 【问题描述】:

我有一个这样的 (label, count) 元组列表:

[('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

但是有没有更 Pythonic/优雅/有效的方法来做到这一点?

【问题讨论】:

【参考方案1】:

使用 itertools 和列表推导

import itertools

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

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

【讨论】:

要使用 groupby,您必须首先确保序列已预先分组(所有“葡萄”相邻,等等)。一种方法是先对序列进行排序 @Thomas Wouters,是的,你是对的(“相同的标签总是相邻的”)【参考方案2】:

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

【讨论】:

我喜欢用operator.itemgetter 代替lambda 这要求列表按第一个键排序。如果它还没有排序,那么 ghostdog74 的 defaultdict 方法是一个更好的解决方案。 为什么要使用operator 而不是lambda【参考方案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)

【讨论】:

这会在 alist 中搜索每个项目,这会使您的算法 O(n^2) 不是一件好事。【参考方案4】:
>>> 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)]

【讨论】:

【参考方案5】:

或者更简单更易读的答案(不带 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)

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案7】:

方法

def group_by(my_list):
    result = 
    for k, v in my_list:
        result[k] = v if k not in result else result[k] + v
    return result 

用法

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

group_by(my_list) 

# Output: 'grape': 103, 'apple': 29, 'banana': 3

您转换为像list(group_by(my_list).items()) 这样的元组列表。

【讨论】:

以上是关于分组 Python 元组列表的主要内容,如果未能解决你的问题,请参考以下文章

如何根据某些文本标准对元组列表进行分组/存储?

如何将列表项分组为元组? [复制]

按项目分组元组列表

python数据结构之列表字典元组集合

如何对元组列表进行分组?

Python的列表和元组的区别