【问题标题】:How to iterate two files with different steps without loading them all in memory using python?如何使用python迭代两个具有不同步骤的文件而不将它们全部加载到内存中?
【发布时间】:2017-07-21 03:28:21
【问题描述】:

假设我有两个文件 A 和 B

在A中我有100行,在B中我有10行,我需要对A中的每10行和B中的每1行进行一次操作。

例如在 A 中,我有以下几行 a1 a2 ... a10 a11 .. a20 ... a100

在 B 我有以下几行: b1 b2 ... b10

我想对数据a1、a2..a10和b1做一个操作,我想对数据a11、a12...a20和b2再做一次操作。

所以问题是 A 和 B 都非常大,我无法将它们全部加载到内存中,所以我需要逐行迭代它们,但速度不同,因为 A 中的 10 行映射到 B 中的 1 行。如何要做到这一点而不预处理 A 以使其与 B 具有相同的行大小?

(我使用python 2.7)

【问题讨论】:

标签: python algorithm


【解决方案1】:

有一个常见的习惯用法是使用itertools.izip 和对单个迭代器的引用的解包列表来迭代“块”:

from itertools import izip

for values in izip(*[iter]*n): # values will hold n values at a time

出于您的目的,您可以添加对较小文件的引用以及对较大文件的多个引用(文件是迭代器):

with open("A") as file_a, open("B") as file_b:
    for values in izip(file_b, *[file_a]*10): # values will have one B value and 10 A values
        # do stuff here with the values

如果文件可能不完全对齐,您可以使用itertools.izip_longest 而不是常规的izip。如果输入不完全正确匹配,它将允许您提供要使用的默认值。在 Python 3 中,常规内置函数 zip 的工作方式与 Python 2 中的 itertools.izip 类似,因此您无需导入任何内容。

【讨论】:

  • 这是适用于 Python 3.X 的绝佳解决方案。 for 循环中的解包语法不在 Python 2.7(OP 正在使用)中。你必须更新为for all_values in ... b_values, a_values = all_values[0], all_values[1:]
  • 哦,对了。我最初的解决方案都是 Python 3(使用普通的zip),我认为我已经将所有内容都向后移植了,但我想不是。好吧,我猜你可以在一个元组中获取整个值集,然后手动解包。
【解决方案2】:

标准的file.readline 方法将为您提供单行读取。打开文件对象不会一次将它们全部加载到内存中;文件被缓冲并且文件位置随着后续的 readlines 被调用而提前。通过这种方式,您可以像这样完成您正在寻找的东西:

def process(a_data, b_data):
    pass  # Your code here

a_data = [None] * 10
with open('pathToFileB', 'r') as fileB:
    with open('pathToFileA', 'r') as fileA:
        for b_data in fileB:
            for i in len(a_data):
                a_data[i] = a.readline()
            process(a_data, b_data)

当然,这是假设文件 A 保证文件 B 中的每一行都有 10 行;当到达文件A的末尾时,如果文件B中还有行,a_data将被None值填充。

【讨论】:

    【解决方案3】:

    您可以编写一些通用代码来打印文件a.txtb.txt 中的行,具体取决于它们有多少行。

    您可以像下面这样动态地派生它,甚至可以在下面的代码中硬编码间隔 (factor=10)。

    NOTE:对于我的示例执行,a.txt 有 a1..a33(33 行),b.txt 有 b1..b3(3 行)

    import math
    
    ## capture all data from files into a list    
    alines = [line.rstrip('\n') for line in open('a.txt')]
    blines = [line.rstrip('\n') for line in open('b.txt')]
    
    ## you can have your own custom factor too
    ## e.g. 10 as you explain in question
    factor = math.ceil(len(alines) / len(blines))
    print("Your factor is: " + str(factor))
    print("\n")
    
    acount = 0
    bcount = 0
    
    ## iterate thru all elements of a and b file
    for line in range(len(alines) + len(blines)):
        ## print b only when its turn
        if (bcount < len(blines) and (line % (factor+1)) == 0):
            print(blines[bcount])
            bcount = bcount + 1
        else:
            ## print a when its turn
            if (acount < len(alines)):
                print(alines[acount])
                acount = acount + 1
    

    样品运行

    b1
    a1
    a2
    a3
    a4
    a5
    a6
    a7
    a8
    a9
    a10
    a11
    b2
    a12
    a13
    a14
    a15
    a16
    a17
    a18
    a19
    a20
    a21
    a22
    b3
    a23
    a24
    a25
    a26
    a27
    a28
    a29
    a30
    a31
    a32
    a33
    

    【讨论】:

      猜你喜欢
      • 2021-08-16
      • 2013-10-07
      • 1970-01-01
      • 2016-08-24
      • 1970-01-01
      • 1970-01-01
      • 2012-08-03
      • 2020-08-21
      • 1970-01-01
      相关资源
      最近更新 更多