2012-08-09 31 views
2

我有一个大名单,其中摘录的样子:累加,同时遍历列表

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

请在将来使用pprint.pprint或手动格式化您的代码。也请在将来添加'python'标签。谢谢! – ninjagecko 2012-08-09 08:30:44

+2

在我的愚见中,根据“预期结果”,你不清楚你想要做什么。 *编辑*:我看到了,你想分割清单,然后做累计总和。 – ninjagecko 2012-08-09 08:33:18

+1

我也不明白你的目标。而且我无法推断'power'应该如何产生'new'。请更详细地描述*你想成为什么样的人。 – 2012-08-09 08:35:23

回答

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站上。

例如,

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)] 

然后积聚调用的每个列,下面是什么样子:

>>> [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)] 
+0

这个输出是完美的,除了我需要插入一个标记或甚至插入站号,所以我知道什么累加是属于哪些站,例如, '1234'在输出列表的开头(或从结尾第二个)和'1567'第二个最后一个列表(或最后一个),作为一个指示符。我把这些内容写成'####站号1234 ###'的末尾在我期望的结果中,但是我意识到这可能是一个interperted作为评论,我的坏。 – user1532369 2012-08-09 09:25:02

+0

我也有python 2。7 - 谢谢:) – user1532369 2012-08-09 09:26:41

+0

@ user1532369我给了两个结构,字典和列表与电台作为关键。 – jamylak 2012-08-09 09:44:33

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函数以符合您的定义。