2012-08-09 27 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函數以符合您的定義。