2013-04-09 50 views
2

我有以下列格式的一些數據:發電機功能僅產生第一項

data = """ 

[Data-0] 
Data = BATCH 
BatProtocol = DIAG-ST 
BatCreate = 20010724 

[Data-1] 
Data = SAMP 
SampNum = 357 
SampLane = 1 

[Data-2] 
Data = SAMP 
SampNum = 357 
SampLane = 2 

[Data-9] 
Data = BATCH 
BatProtocol = VCA 
BatCreate = 20010725 

[Data-10] 
Data = SAMP 
SampNum = 359 
SampLane = 1 

[Data-11] 
Data = SAMP 
SampNum = 359 
SampLane = 2 

""" 

結構是:

  1. [Data-x]其中x是一個數
  2. Data =接着爲無論BATCHSAMPLE
  3. 更多行

我想寫一個函數,爲每個'批'產生一個列表。列表中的第一項是包含行Data = BATCH的文本塊,列表中的以下項目是包含行Data = SAMP的文本塊。我現在有

def get_batches(data): 
    textblocks = iter([txt for txt in data.split('\n\n') if txt.strip()]) 
    batch = [] 
    sample = next(textblocks) 
    while True: 
     if 'BATCH' in sample: 
      batch.append(sample) 
     sample = next(textblocks) 
     if 'BATCH' in sample: 
      yield batch 
      batch = [] 
     else: 
      batch.append(sample) 

如果這樣調用:

batches = get_batches(data) 
for batch in batches: 
    print batch 
    print '_' * 20 

它,但是,只返回第一個 '批':

['[Data-0]\nData = BATCH\nBatProtocol = DIAG-ST\nBatCreate = 20010724', 
'[Data-1]\nData = SAMP\nSampNum = 357\nSampLane = 1', 
'[Data-2]\nData = SAMP\nSampNum = 357\nSampLane = 2'] 
____________________ 

Wheras我的預期輸出是:

['[Data-0]\nData = BATCH\nBatProtocol = DIAG-ST\nBatCreate = 20010724', 
'[Data-1]\nData = SAMP\nSampNum = 357\nSampLane = 1', 
'[Data-2]\nData = SAMP\nSampNum = 357\nSampLane = 2'] 
____________________ 
['[Data-9]\nData = BATCH\nBatProtocol = VCA\nBatCreate = 20010725', 
'[Data-10]\nData = SAMP\nSampNum = 359\nSampLane = 1', 
'[Data-11]\nData = SAMP\nSampNum = 359\nSampLane = 2'] 
____________________ 

我在想什麼或者如何改善我的功能?

+1

如果你想解析看起來像這樣的文件,看看['ConfigParser'模塊](http://docs.python.org/2/library/configparser.html)。 – Blender 2013-04-09 19:31:23

+0

另外:不是'iter([some listcomp here])',你可以寫'(某個genexp在這裏)'。 – DSM 2013-04-09 19:35:43

回答

2

正如@FJ所解釋的,你的代碼的真正問題是你不會產生最後一個值。但是,還可以進行其他改進,其中一些改進可以更輕鬆地解決最後一個值問題。

在我第一次看到你的代碼時,我最喜歡的一個是if陳述,檢查'BATCH' in sample,它可以合併爲一個。

這裏有一種說法是這樣做,以及使用上發電機的for循環,而不是while True

def get_batches(data): 
    textblocks = (txt for txt in data.split('\n\n') if txt.strip()) 
    batch = [next(textblocks)] 
    for sample in textblocks: 
     if 'BATCH' in sample: 
      yield batch 
      batch = [] 
     batch.append(sample) 
    yield batch 

我無條件地在最後屈服batch,因爲沒有情況下,你可以使用batch爲空(如果data爲空,啓動時batch的初始化將提高StopIteration)。

6

當您找到下一批的開始時,您只會產生批次,因此您將永遠不會包含最後一批數據。爲了解決這個問題,你需要像你的函數的末尾以下內容:

if batch: 
    yield batch 

但是隻是這樣做是行不通的。最終,循環內部的next(textblocks)將增加StopIteration,因此while循環後面的代碼無法執行。這裏是讓這只是一個微小的改變你目前的代碼工作的一種方式(請參閱下面的一個更好的版本):

def get_batches(data): 
    textblocks = iter([txt for txt in data.split('\n\n') if txt.strip()]) 
    batch = [] 
    sample = next(textblocks) 
    while True: 
     if 'BATCH' in sample: 
      batch.append(sample) 
     try: 
      sample = next(textblocks) 
     except StopIteration: 
      break 
     if 'BATCH' in sample: 
      yield batch 
      batch = [] 
     else: 
      batch.append(sample) 
    if batch: 
     yield batch 

我建議剛上循環textblocksfor循環,而不是:

def get_batches(data): 
    textblocks = (txt for txt in data.split('\n\n') if txt.strip()) 
    batch = [] 
    for sample in textblocks: 
     if 'BATCH' in sample: 
      if batch: 
       yield batch 
      batch = [] 
     batch.append(sample) 
    if batch: 
     yield batch