我有一个很大的列表,其摘录如下:
power = [
['1234-43211', [5, 6, -4, 11, 22]],
['1234-783411', [43, -5, 0, 0, -1]],
['1234-537611', [3, 0, -5, -6, 0]],
['1567-345411', [4, 6, 8, 3, 3]],
['1567-998711', [1, 2, 1, -4, 5]]
]
字符串中的第一个数字是重要的数字,也是我希望将我的添加内容分开的数字。即我只想累加每个站内的值(并返回每个单一的累积加法),永远不要添加两个不同的值。
我的目标是迭代此列表并累加地添加一个工作站的int值,返回每个添加,然后在列表中检测到下一个工作站时再次启动。
期望的结果:
new = [
[48, 1, -4, 11, -21],
[ 51, 1, -9, 5, -21], '### End of '1234' ### '
[5, 8, 9, -1, 8], '### End of 1567 ###'
] or something similar to this
我尝试了以下内容:
for i in range(len(power)-1):
front_num_1 = power[i][0].split('-')[0]
front_num_2 = power[i+1][0].split('-')[0]
station = '%s' % (front_num_1)
j = power[i][1]
k = power[i+1][1]
if front_num_1 == front_num_2:
print [k + j for k, j in zip(j, k)]
elif front_num_1 != front_num_2:
print '#####################################
else:
print 'END'
然而,这种添加不是累积的,因此没有用处。
答案 0 :(得分:2)
from itertools import groupby, islice
def accumulate(iterable): # in py 3 use itertools.accumulate
''' Simplified version of accumulate from python 3'''
it = iter(iterable)
total = next(it)
yield total
for element in it:
total += element
yield total
power = [
['1234-4321-1', [5, 6, -4, 11, 22]],
['1234-7834-1', [43, -5, 0, 0, -1]],
['1234-5376-1', [3, 0, -5, -6, 0]],
['1567-3454-1', [4, 6, 8, 3, 3]],
['1567-9987-1-', [1, 2, 1, -4, 5]]
]
groups = ((k, (nums for station, nums in g))
for k, g in
groupby(power, lambda x: x[0].partition('-')[0]))
new = [(station, zip(*(islice(accumulate(col), 1, None) for col in zip(*nums))))
for station, nums in groups]
print new
print dict(new) # or as a dictionary which is unordered
<强>输出强>
[('1234', [(48, 1, -4, 11, 21), (51, 1, -9, 5, 21)]), ('1567', [(5, 8, 9, -1, 8)])]
{'1234': [(48, 1, -4, 11, 21), (51, 1, -9, 5, 21)], '1567': [(5, 8, 9, -1, 8)]}
这是如何运作的:
首先,使用itertools.groupby
基于电台对列表进行分组。
EG。
nums = [[5, 6, -4, 11, 22],
[43, -5, 0, 0, -1],
[3, 0, -5, -6, 0]]
是第一组。正如你所看到的那样,它是一个矩阵的形式。
zip(*nums)
使用参数解包来转置矩阵。它叫
zip([5, 6, -4, 11, 22], [43, -5, 0, 0, -1], [3, 0, -5, -6, 0])
创建列表:
cols = [(5, 43, 3), (6, -5, 0), (-4, 0, -5), (11, 0, -6), (22, -1, 0)]
然后在每列上调用accumulate,这是看起来的样子:
>>> [list(accumulate(col)) for col in cols]
[[5, 48, 51], [6, 1, 1], [-4, -4, -9], [11, 11, 5], [22, 21, 21]]
正如您所看到的,每个列表中的第一个元素不是必需的,因此islice
用于从索引1
获取元素,然后结束(None
)。这是看起来像:
>>> [list(islice(accumulate(col), 1, None)) for col in cols]
[[48, 51], [1, 1], [-4, -9], [11, 5], [21, 21]]
现在我们只需要将其转换回来。
>>> zip(*(islice(accumulate(col), 1, None) for col in cols))
[(48, 1, -4, 11, 21), (51, 1, -9, 5, 21)]
答案 1 :(得分:0)
如果你将问题分解成更小的部分会有所帮助。我似乎明白你想要1)根据一些标准拆分你的列表,然后2)取每个子列表的累积和(考虑每个元素一个向量)。
例如:
stationList = [
['1234-4321-1', [5, 6, -4, 11, 22]],
['1234-7834-1', [43, -5, 0, 0, -1]],
['1234-5376-1', [3, 0, -5, -6, 0]],
['1567-3454-1', [4, 6, 8, 3, 3]],
['1567-9987-1-', [1, 2, 1, -4, 5]]
]
变为:
{'1234-4321-1': [
<5, 6, -4, 11, 22>,
<5, 6, -4, 11, 22> + <43, -5, 0, 0, -1>,
<5, 6, -4, 11, 22> + <43, -5, 0, 0, -1> + <3, 0, -5, -6, 0>
],
'1567-3454-1': [
<4, 6, 8, 3, 3>,
<4, 6, 8, 3, 3> + <1, 2, 1, -4, 5>
]
}
(我使用<...>
来表示假设的Vector
对象,或仅仅将列表视为向量。)
<强>解决方案强>
from itertools import *
1)要根据某些标准拆分列表,请使用itertools.groupby:documentation here。或者写一个生成器函数。
getStation = lambda x: x[0].split('-')[0]
def groupby_station(inputList):
return groupby(inputList, key=getStation)
2)累积和可以写为生成函数。您可以使用numpy
,也可以自己编写。
def listAdd(*lists):
"""
listAdd([1,2,3], [10,20,30]) -> [11,22,33]
listAdd([1,2,3], []) -> [1,2,3]
"""
return [sum(xs) for xs in zip_longest(*lists, fillvalue=0)]
def cumSum(lists):
"""
cumSum([1,2],[10,20],[100,200]) -> ([1,2],[11,22],[111,222])
"""
total = []
for list in lists:
total = listAdd(total, list)
yield total
现在只需将两者结合起来:
{key:cumSum(*lists) for key,lists in groupby_station(inputList)}
请注意,我对累积金额的定义与您的略有不同;您可以修改cumSum
函数以匹配您的定义。