如何基于Python中第一个列表的相同元素对3个大小相同的排序列表求和?

如何基于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,

我有一本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, 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