2013-04-09 46 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