【问题标题】:Python scan file line by line and remove last line in the same loopPython逐行扫描文件并删除同一循环中的最后一行
【发布时间】:2015-01-26 16:22:38
【问题描述】:

我正在尝试扫描 csv 文件并逐行进行调整。最后,我想删除最后一行。如何删除同一扫描循环中的最后一行?

我下面的代码从原始文件中读取,进行调整,最后写入一个新文件。

import csv

raw_data = csv.reader(open("original_data.csv", "r"), delimiter=",")
output_data = csv.writer(open("final_data.csv", "w"), delimiter=",")
lastline = # integer index of last line

for i, row in enumerate(raw_data):
    if i == 10:
        # some operations
        output_data.writerow(row)
    elif i > 10 and i < lastline:
        # some operations
        output_data.writerow(row)
    elif i == lastline:
        output_data.writerow([])
    else:
        continue

【问题讨论】:

  • 从哪个文件中删除最后一行?原始输入文件?
  • @Evert 删除 output_data 中的最后一行。
  • 如果要删除最后一行,为什么要先写呢?
  • @Evert 我从一个名为 original_data.csv 的文件开始。我不知道有多少行。 final_data.csv 是我创建的所有调整后的输出文件。经过所有调整,我不想保留原始文件的最后一行。但是,我如何知道一行是否是最后一行?
  • 你也许可以简单地切片raw_data:for i, row in enumerate(raw_data[:-1]):

标签: python python-2.7


【解决方案1】:

您可以制作一个生成器来生成除最后一个之外的所有元素:

def remove_last_element(iterable):
    iterator = iter(iterable)
    try:
        prev = next(iterator)
        while True:
            cur = next(iterator)
            yield prev
            prev = cur
    except StopIteration:
        return

然后你只需将raw_data 包裹在其中:

for i, row in enumerate(remove_last_element(raw_data)):
    # your code

最后一行将被自动忽略。

这种方法的好处是只读取文件一次。

【讨论】:

    【解决方案2】:

    @Kolmar's idea 的变体:

    def all_but_last(it):
        buf = next(it)
        for item in it:
            yield buf
            buf = item
    
    for line in all_but_last(...):
    

    下面是更通用的代码,扩展了 islice(双参数版本)用于负索引:

    import itertools, collections
    
    def islice2(it, stop):
        if stop >= 0:
            for x in itertools.islice(it, stop):
                yield x
        else:
            d = collections.deque(itertools.islice(it, -stop))
            for item in it:
                yield d.popleft()
                d.append(item)
    
    
    for x in islice2(xrange(20), -5):
        print x,
    
    # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
    

    【讨论】:

    • 这是一个很好的修改,只需要注意itertools.islice 也有可选的startstep 参数
    • @Kolmar:是的,但我太懒了;)islice2(xs, 100, 0, -5) 听起来工作量很大。
    【解决方案3】:

    您可以使用大小为 2 的窗口进行迭代,并仅打印窗口中的第一个值。这将导致最后一个元素被跳过:

    from itertools import izip, tee
    
    def pairwise(iterable):
        a, b = itertools.tee(iterable)
        next(b, None)
        return izip(a, b)
    
    for row, _ in pairwise(raw_data):
        output_data.writerow(row)
    
    output_data.writerow([])
    

    【讨论】:

    • 值得注意的是,此方法使用列表乘法复制引用的事实,因此结果是对同一迭代器的一对引用,每个循环都会以两倍的速度递增。
    • @kroolik 我已经编辑了答案。应该是pairwice,而不是石斑鱼。谢谢!
    【解决方案4】:

    一个想法是计算您迭代的每一行的长度,然后在到达最后一行时截断文件,从而“缩短文件”。不确定这是否是一种好习惯...

    例如 Python: truncate a file to 100 lines or less

    【讨论】:

      【解决方案5】:

      不要在每次循环迭代时写入当前行,而是尝试写入之前读取的行:

      import csv
      
      raw_data = csv.reader(open("original_data.csv", "r"), delimiter=",")
      output_data = csv.writer(open("final_data.csv", "w"), delimiter=",")
      last_iter = (None, None)
      
      try:
          last_iter = (0, raw_data.next())
      except StopIteration:
          # The file is empty
          pass
      else:
          for new_row in raw_data:
              i, row = last_iter
              last_iter = (i + 1, new_row)
      
              if i == 10:
                  # some operations
                  output_data.writerow(row)
              elif i > 10:
                  # some operations
                  output_data.writerow(row)
      
          # Here, the last row of the file is in the `last_iter` variable.
          # It won't get written into the output file.
          output_data.writerow([])
      

      【讨论】:

        猜你喜欢
        • 2010-12-25
        • 2015-04-26
        • 2013-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多