如何基于Python中第一个列表的相同元素对3个大小相同的排序列表求和?
我有一本python如何基于Python中第一个列表的相同元素对3个大小相同的排序列表求和?,python,list,dictionary,sum,iteration,Python,List,Dictionary,Sum,Iteration,我有一本python词典包含3个列表,分别位于“time”、“power”和“usage”键中。 所有列表都有相同数量的元素,并且所有列表都已排序。什么 我想做的是总结列表中的所有元素,包括它们的索引“power”和“usage” 对应于列表“时间”中的相同值,以便每个时间单位只有一个功率和使用率样本 例如,转换此词典: {'time': [1, 2, 2, 3, 4, 4, 5], 'power': [2, 2, 3, 6, 3, 3, 2], 'usage': [0, 1, 1, 2,
词典
包含3个列表
,分别位于“time”、“power”和“usage”键中。
所有列表都有相同数量的元素,并且所有列表都已排序。什么
我想做的是总结列表中的所有元素,包括它们的索引“power”和“usage”
对应于列表“时间”中的相同值,以便每个时间单位只有一个功率和使用率样本
例如,转换此词典:
{'time': [1, 2, 2, 3, 4, 4, 5],
'power': [2, 2, 3, 6, 3, 3, 2],
'usage': [0, 1, 1, 2, 1, 4, 7]}
d = {'time': [1, 2, 2, 3, 4, 4, 5],
'power': [2, 2, 3, 6, 3, 3, 2],
'usage': [0, 1, 1, 2, 1, 4, 7]}
print aggregate(d)
>>>
{'usage': [0, 2, 2, 5, 7], 'power': [2, 5, 6, 6, 2], 'time': [1, 2, 3, 4, 5]}
对于这一点:
{'time': [1, 2, 3, 4, 5],
'power': [2, 5, 6, 6, 2],
'usage': [0, 2, 2, 5, 7]}
我已经写了这段代码,但我不喜欢
这太多了:
d = {'time':[1,2,2,3,4,4,5], 'power':[0,1,1,2,1,4,7], 'usage':[2,2,3,6,3,3,2]}
prev = -1
new_d = {'time':[], 'power': [], 'usage':[]}
indexes = range( len(d['time']) )
for i in indexes:
if d['time'][i]!=prev:
new_d['time'].append(d['time'][i])
new_d['power'].append(d['power'][i])
new_d['usage'].append(d['usage'][i])
else:
last_power = len( new_d['power'] ) - 1
last_usage = len( new_d['usage'] ) - 1
new_d['power'][last_power]+=d['power'][i]
new_d['usage'][last_usage]+=d['usage'][i]
prev=d['time'][i]
print d
print new_d
有没有一种pythonian方法可以更简单、更全面地实现这一点 一个健壮的解决方案,可以处理任意数量的额外字段-按“时间”字段排序(作为一种方法): 使用字典:
{'time': [1, 2, 2, 3, 4, 4, 5],
'power': [2, 2, 3, 6, 3, 3, 2],
'usage': [0, 1, 1, 2, 1, 4, 7]}
d = {'time': [1, 2, 2, 3, 4, 4, 5],
'power': [2, 2, 3, 6, 3, 3, 2],
'usage': [0, 1, 1, 2, 1, 4, 7]}
print aggregate(d)
>>>
{'usage': [0, 2, 2, 5, 7], 'power': [2, 5, 6, 6, 2], 'time': [1, 2, 3, 4, 5]}
这就是“蟒蛇之道”:
您可以对任意数量的额外字段使用以下方法:
from itertools import groupby
from operator import itemgetter
dic = {'time': [1, 2, 2, 3, 4, 4, 5],
'power': [2, 2, 3, 6, 3, 3, 2],
'usage': [0, 1, 1, 2, 1, 4, 7]}
aggrigated = {}
fields = dic.items()
for field in fields:
aggrigated[field[0]] = [sum(y[1] for y in x)
for k,x in groupby(
zip(fields[0][1], field[1]),
key=itemgetter(0))
]
改进版借鉴Ashwini Chaudhary的答案。使用
itertools.groupby
,zip
和一些列表理解:
In [55]: dic={'time': [1, 2, 2, 3, 4, 4, 5],
....: 'power': [2, 2, 3, 6, 3, 3, 2],
....: 'usage': [0, 1, 1, 2, 1, 4, 7]}
In [56]: from itertools import groupby
In [57]: from operator import itemgetter
In [58]: zip1=zip(dic['time'],dic['power']) #use `itertools.izip` for performance
In [59]: [sum(x[1] for x in v) for k,v in groupby(zip1,key=itemgetter(0))]
Out[59]: [2, 5, 6, 6, 2]
In [60]: zip2=zip(dic['time'],dic['usage'])
In [61]: [sum(x[1] for x in v) for k,v in groupby(zip2,key=itemgetter(0))]
Out[61]: [0, 2, 2, 5, 7]
In [64]: timee=[k for k,v in groupby(dic['time'])]
In [65]: timee
Out[65]: [1, 2, 3, 4, 5]
zip1
是[(1,2)、(2,2)、(2,3)、(3,6)、(4,3)、(4,3)、(5,2)]
,现在您可以使用itertools.groupby>基于第一项对元素进行分组,然后获取返回组中每个元组的第二个元素的总和
In [75]: new_time=[k for k,v in groupby(dic['time'])]
In [76]: new_power=[sum(x[1] for x in v) for k,v in groupby(zip1,key=itemgetter(0))]
In [77]: new_usage=[sum(x[1] for x in v) for k,v in groupby(zip2,key=itemgetter(0))]
In [80]: dict(zip(('time','power','usage'),(new_time,new_power,new_usage)))
Out[80]: {'power': [2, 5, 6, 6, 2], 'time': [1, 2, 3, 4, 5], 'usage': [0, 2, 2, 5, 7]}
我会先把这些值组合成一个新的dict,然后求和。占用更多空间,但操作简单快捷:
from collections import defaultdict
from itertools import groupby
power = defaultdict(list)
usage = defaultdict(list)
for i, time in enumerate(data['time']):
power[time].append(data['power'][i])
usage[time].append(data['usage'][i])
times = [key for key,group in groupby(data['time'])]
print { 'time': times,
'power' : [sum(power[time]) for time in times],
'usage' : [sum(usage[time]) for time in times]
}
对于可变数量的键,我添加了keys
变量以避免重写它们:
>>> from itertools import groupby
>>> from operator import itemgetter
>>> keys = ('time', 'power', 'usage')
>>> groups = groupby(zip(*[d[k] for k in keys]), key=itemgetter(0))
>>> lists = zip(*[[k] + map(sum, zip(*g)[1:]) for k, g in groups])
>>> dict(zip(keys, lists))
{'usage': (0, 2, 2, 5, 7), 'power': (2, 5, 6, 6, 2), 'time': (1, 2, 3, 4, 5)}
这里有一个可以处理任意字典的。。。。(其中,d
是您的指令…)
下面是我问题的精确解决方案。我是根据jamylak的回答做的
我认为这是最“pythonian”和最全面的解决方案。我
我们所做的就是修改他的代码,以便处理多个字段,即多个字段
字典中的列表。我已经接受了jamylak的答案,下面是解决方案
对于多个字段:
from itertools import groupby
from operator import itemgetter
d = {'power': [2, 2, 3, 6, 3, 3, 2],
'usage': [0, 1, 1, 2, 1, 4, 7],
'time': [1, 2, 2, 3, 4, 4, 5]}
# construct a list with all the key names (starting from 'time')
keys = ['time'] + [key for key in d.keys() if key!='time']
# construct a list with all the keys' lists (starting from the one of 'time')
keys_lists = [ d['time'] ] + [d[key] for key in d.keys() if key!='time']
groups = groupby(zip(*keys_lists), key=itemgetter(0))
lists = zip(*[[k] + map(sum, zip(*g)[1:]) for k, g in groups])
new_d = dict(zip((keys), lists))
print new_d
事实上,我有一本字典,里面有20个不同的列表,其中包含更多关于权力和用法的信息。并不是所有的列表都经过了排序=P。或者至少power
和usage
似乎有一些奇怪的标准。它看起来更像是将元组(时间、功率、用法)
存储为命名列表。它们通过time
字段进行排序,您希望对其进行压缩。但这仍然是可以理解的。如果我一切都对了,哈哈。你还想对所有其他字段进行求和吗?你做错了。您应该有一个对象列表,每个对象都有时间
、功率
和使用
字段(以及其他20个字段)。这将使您的代码更简单、更清晰、更具python风格,并使处理变得更容易。您打算接受答案吗?还是你的问题还没有解决?如果有什么问题,请告诉我。你的答案很好,但我想找一些更简单、更全面的。我在jamylak的回答中找到了。我在他的回答中添加了适用于多个字段的代码。看“Thanasis Petsas的编辑”的结尾是的,好的。这种方式似乎比我的更全面。@ThanasisPetsas编辑了我的答案,为任意大小的dict提供了一个强大的解决方案。谢谢!现在好多了!:)再次编辑它以更清楚地了解正在发生的事情,并通过迭代新的数据来提高效率。我使用真实数据运行您的代码,得到了一个索引器:lst[-1]+=old\u d[key][I]
索引器:列表索引超出范围这不会更快。对于每个时间
,您都会查找电源
和使用
的每个列表。。那太过分了,太酷了!我想我可以很容易地遍历字典键并执行此操作,因为我的真实数据是一个包含20个列表的字典,而不仅仅是3个列表:)是的,它很容易扩展。我不确定这种方法,因为首先你无法确定你是否将正确的键连接到了正确的列表。我有一种感觉,随着领域的增多,这将增加复杂性。。但是我不确定。@InbarRose在这个方法中一切都是完全确定的。键的顺序决定了这一点。我也可以很容易地将其应用于更多的字段,我只需要创建一个keys
变量,这样就不必编写每个字段twice@jamylak我很感兴趣的是,在你将它扩展到x字段后,这将是一个什么样的方法。好的,我自己做的。你的回答帮我做了我想做的事!我已经添加到您的答案代码适应多个领域!非常感谢你!是的,非常好看的方法,但是你能扩展它吗?我不确定你在这里做什么。新的dict在哪里?@InbarRose您只需将这些列表理解分配给新的dict,就可以获得所需的dict。整个事情似乎不容易扩展,而且在所有[in/out]都在进行的情况下,试图理解代码让我头疼。。。。布莱!但答案是正确的这与我编造的答案几乎完全相同,但我决定不发布。当然,我硬编码了字段
和agg
,并且在返回之前使用了defaultdict(list)
而不是普通dict(设置out.default\u factory=None
)。
from itertools import izip
def m_(time, power, usage):
time_, power_, usage_ = [], [], []
for t, p, u in izip(time, power, usage):
if not time_:
time_.append( t )
power_.append( 0 )
usage_.append( 0 )
if time_[-1] == t:
power_[-1] += p
usage_[-1] += u
else:
time_.append( t )
power_.append( p )
usage_.append( u )
time[:], power[:], usage[:] = time_, power_, usage_
if __name__ == '__main__':
d = {'time':[1,2,2,3,4,4,5], 'power':[0,1,1,2,1,4,7], 'usage':[2,2,3,6,3,3,2]}
m_(**d)
print d
from itertools import groupby, imap
from operator import itemgetter
def group_dict_by(mapping, field, agg=sum):
grouper = mapping[field]
new_grouper = []
accum = {k: [] for k in mapping.viewkeys() - [field]}
for key, grp in groupby(enumerate(grouper), itemgetter(1)):
new_grouper.append(key)
idx = [g[0] for g in grp]
for dk, dv in accum.iteritems():
dv.append(agg(imap(mapping[dk].__getitem__, idx)))
accum[field] = new_grouper
return accum
print group_dict_by(d, 'time')
# {'usage': [0, 2, 2, 5, 7], 'power': [2, 5, 6, 6, 2], 'time': [1, 2, 3, 4, 5]}
from itertools import groupby
from operator import itemgetter
d = {'power': [2, 2, 3, 6, 3, 3, 2],
'usage': [0, 1, 1, 2, 1, 4, 7],
'time': [1, 2, 2, 3, 4, 4, 5]}
# construct a list with all the key names (starting from 'time')
keys = ['time'] + [key for key in d.keys() if key!='time']
# construct a list with all the keys' lists (starting from the one of 'time')
keys_lists = [ d['time'] ] + [d[key] for key in d.keys() if key!='time']
groups = groupby(zip(*keys_lists), key=itemgetter(0))
lists = zip(*[[k] + map(sum, zip(*g)[1:]) for k, g in groups])
new_d = dict(zip((keys), lists))
print new_d