我有以下元组列表:[('a', 1), ('a', 1), ('b', 1), ('c',1), ('a', 1), ('c', 1)]
我想知道我是否可以利用python的reduce
函数来聚合它们并产生以下输出:[('a', 3), ('b', 1), ('c', 2)]
或者,如果还有其他方法,我也想知道(循环很好)
答案 0 :(得分:3)
使用reduce
似乎很难实现,因为如果你“减少”的两个元组都不具有相同的字母,则无法计算结果。如何将('a',1)
和('b',1)
降低到一些可行的结果?
我能做的最好的事情是l = functools.reduce(lambda x,y : (x[0],x[1]+y[1]) if x[0]==y[0] else x+y,sorted(l))
它让我('a', 3, 'b', 1, 'c', 1, 'c', 1)
。所以它适用于第一个元素,但是需要不止一个传递来完成其他元素(重新创建元组并创建另一个类似reduce
,好吧,至少可以说效率不高!)。
无论如何,这里有2种工作方式
首先,使用collections.Counter
计数相同类型的元素:
l = [('a', 1), ('a', 1), ('b', 1), ('c',1), ('a', 1), ('c', 1)]
import collections
c = collections.Counter()
for a,i in l:
c[a] += i
我们不能使用listcomp,因为每个元素都有一个权重(即使这里是1)
结果:字典:Counter({'a': 3, 'c': 2, 'b': 1})
第二个选项:在排序列表上使用itertools.groupby
,按名称/字母分组,并对带有相同字母的整数执行求和:
print ([(k,sum(e for _,e in v)) for k,v in itertools.groupby(sorted(l),key=lambda x : x[0])])
结果:
[('a', 3), ('b', 1), ('c', 2)]
答案 1 :(得分:1)
使用defaultdict子类和sum函数的替代方法:
import collections
l = [('a', 1), ('a', 1), ('b', 1), ('c',1), ('a', 1), ('c', 1)]
d = collections.defaultdict(list)
for t in l:
d[t[0]].append(t[1])
result = [(k,sum(v)) for k,v in d.items()]
print(result)
输出:
[('b', 1), ('a', 3), ('c', 2)]
答案 2 :(得分:0)
另一种方法是创建自定义的reduce函数。
例如:
l = [('a',1),('a',1),('b',1),('c',1),('a',1),('c',1) ]
def myreduce(func , seq):
output_dict = {}
for k,v in seq:
output_dict[k] = func(output_dict.get(k,0),v)
return output_dict
myreduce((lambda sum,value:total + sum),l)
输出:
{'a':3,'b':1,'c':2}
之后,您可以将生成的输出修改为元组列表。