如何避免创建不必要的列表?

2024-04-19 00:11:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我经常遇到这样的情况:我从文件或任何地方提取一些信息,然后必须通过几个步骤将数据转换为最终所需的形式。例如:

def insight_pull(file):
    with open(file) as in_f:
        lines = in_f.readlines()

        dirty = [line.split('    ') for line in lines]
        clean = [i[1] for i in dirty]
        cleaner = [[clean[i],clean[i + 1]] for i in range(0, len(clean),2)]
        cleanest = [i[0].split() + i[1].split() for i in cleaner]


        with open("Output_File.txt", "w") as out_f:
            out_f.writelines(' '.join(i) + '\n' for i in cleanest)

如上例所示:

    # Pull raw data from file splitting on '   '.
    dirty = [line.split('    ') for line in lines]

    # Select every 2nd element from each nested list.
    clean = [i[1] for i in dirty]

    # Couple every 2nd element with it's predecessor into a new list.
    cleaner = [[clean[i],clean[i + 1]] for i in range(0, len(clean),2)]

    # Split each entry in cleaner into the final formatted list.
    cleanest = [i[0].split() + i[1].split() for i in cleaner]

既然我不能将所有的编辑放在一行或一个循环中(因为每个编辑都依赖于它之前的编辑),有没有更好的方法来构造这样的代码?你知道吗

如果问题有点模糊,我道歉。任何意见都将不胜感激。你知道吗


Tags: inclean编辑foraswithlineopen
3条回答

从您的示例中,我假设只有cleanest列表对您有任何实际价值,其余的只是中间步骤,可以毫无顾虑地丢弃。你知道吗

假设是这样,为什么不在每个中间步骤中重用相同的变量,这样就不会在内存中保存多个列表了?你知道吗

def insight_pull(file):
    with open(file) as in_f:
        my_list = in_f.readlines()

        my_list = [line.split('    ') for line in my_list]
        my_list = [i[1] for i in my_list]
        my_list = [[my_list[i],my_list[i + 1]] for i in range(0, len(my_list),2)]
        my_list = [i[0].split() + i[1].split() for i in my_list]


    with open("Output_File.txt", "w") as out_f:
        out_f.writelines(' '.join(i) + '\n' for i in my_list)

如果你是从性能的角度考虑,你就是在寻找发电机。生成器非常类似于列表,但它们的计算是延迟的,这意味着每个元素只在需要时生成一次。例如,在下面的序列中,我实际上没有创建3个完整列表,每个元素只计算一次。下面只是生成器的一个使用示例(据我所知,您的代码只是您遇到的问题的一个示例,而不是一个具体问题):

# All even values from 2-18
even = (i*2 for i in range(1, 10))

# Only those divisible by 3
multiples_of_3 = (val for val in even if val % 3 == 0)

# And finally, we want to evaluate the remaining values as hex
hexes = [hex(val) for val in multiples_of_3]
# output: ['0x6', '0xc', '0x12']

前两个表达式是生成器,最后一个只是一个列表。当有很多步骤时,这将节省大量内存,因为您不创建中间列表。请注意,生成器不能被索引,它们只能被计算一次(它们只是值流)。你知道吗

生成器表达式

您不想创建多个列表是正确的。你的列表理解创建了一个完整的新列表,浪费了内存,你在每个列表上循环!你知道吗

@VPfB使用gererators的想法是一个很好的解决方案,如果您的代码中有其他地方可以重用生成器。如果不需要重用生成器,请使用生成器表达式。你知道吗

生成器表达式是惰性的,就像生成器一样,因此当链接在一起时(如这里所示),当调用writelines时,循环将在末尾计算一次。你知道吗

def insight_pull(file):
    with open(file) as in_f:
        dirty = (line.split('    ') for line in in_f)    # Combine with next
        clean = (i[1] for i in dirty)
        cleaner = (pair for pair in zip(clean,clean))    # Redundantly silly
        cleanest = (i[0].split() + i[1].split() for i in cleaner)

        # Don't build a single (possibily huge) string with join
        with open("Output_File.txt", "w") as out_f:
            out_f.writelines(' '.join(i) + '\n' for i in cleanest)

让以上内容与您的问题直接匹配,您可以进一步:

def insight_pull(file):
    with open(file) as in_f:
        clean = (line.split('    ')[0] for line in in_f)
        cleaner = zip(clean,clean)
        cleanest = (i[0].split() + i[1].split() for i in cleaner)

        with open("Output_File.txt", "w") as out_f:
            for line in cleanest:
                out_f.write(line + '\n')

相关问题 更多 >