我正在尝试合并来自多个服务器的日志。每个日志都是一个元组列表(date,count)。date可能会出现多次,并且我希望结果字典能够保存所有服务器的所有计数之和。
date
count
这是我的尝试,例如一些数据:
from collections import defaultdict a=[("13.5",100)] b=[("14.5",100), ("15.5", 100)] c=[("15.5",100), ("16.5", 100)] input=[a,b,c] output=defaultdict(int) for d in input: for item in d: output[item[0]]+=item[1] print dict(output)
这使:
{'14.5': 100, '16.5': 100, '13.5': 100, '15.5': 200}
如预期的那样。
我要去吃香蕉,因为有一位同事看到了密码。 她坚持认为,必须有一种更加Python化和优雅的方法来做到这一点,而这些方法不能嵌套在循环中。有任何想法吗?
我认为没有比这更简单的了:
a=[("13.5",100)] b=[("14.5",100), ("15.5", 100)] c=[("15.5",100), ("16.5", 100)] input=[a,b,c] from collections import Counter print sum( (Counter(dict(x)) for x in input), Counter())
请注意,Counter(也称为多集)是数据的最自然的数据结构(一种元素可以不止一次属于的集合类型,或者等效地-语义为Element->OccurrenceCount的映射。排名第一,而不是元组列表。
Counter
也可能:
from collections import Counter from operator import add print reduce(add, (Counter(dict(x)) for x in input))
使用reduce(add, seq)代替sum(seq, initialValue)通常更灵活,并且允许您跳过传递冗余初始值。
reduce(add, seq)
sum(seq, initialValue)
请注意,您还可以operator.and_用来查找多集的交集而不是总和。
operator.and_
上面的变体非常慢,因为在每个步骤上都会创建一个新的计数器。让我们修复它。
我们知道这会Counter+Counter返回Counter合并后的数据。可以,但是我们要避免额外的创建。让我们Counter.update改用:
Counter+Counter
Counter.update
update(self,iterable = None,** kwds)未绑定collections.Counter方法 像dict.update()一样,但是添加计数而不是替换它们。源可以是可迭代的,字典或其他Counter实例。
update(self,iterable = None,** kwds)未绑定collections.Counter方法
像dict.update()一样,但是添加计数而不是替换它们。源可以是可迭代的,字典或其他Counter实例。
那就是我们想要的。让我们用兼容的函数包装它,reduce看看会发生什么。
reduce
def updateInPlace(a,b): a.update(b) return a print reduce(updateInPlace, (Counter(dict(x)) for x in input))
这仅比OP的解决方案慢一点。
基准 :http : _**//ideone.com/7IzSx (由于使用了 astynax** ,因此更新了另一个解决方案)_
(另外:如果你拼命想要的一行代码,您可以替换updateInPlace通过lambda x,y: x.update(y) or x其工作方式相同,甚至被证明是一个分裂的第二快,但是在可读性失败时不:-))。
updateInPlace
lambda x,y: x.update(y) or x