【问题标题】:Print lines from one file based on contents from another根据另一个文件的内容打印一个文件的行
【发布时间】:2020-02-12 14:20:50
【问题描述】:

我有两个文件,file1.txt 是这样的:

aaaa
cccc
ffff
gggg

file2.txt 看起来像这样:

aaaa  text1
some_random_text_A
bbbb  text2
some_random_text_B
cccc  text3
some_random_text_C
dddd  text4
some_random_text_D
eeee  text5
some_random_text_E
ffff  text6
some_random_text_F
gggg  text7
some_random_text_G
hhhh  text8
some_random_text_H

我开发了一些 Python 代码,它使用 file1.txt 的内容来子集 file2.txt,这样如果在 file2 中找到来自 file1 的字符串,则包含该字符串的 file2 行以及下一行被打印到输出。这是我的代码:

import re

nums=set()

with open("file1.txt") as file1:
    for line in file1:
        nums.add(line.strip())

with open("file2.txt") as file2, open("out.txt", "wt") as 
outfile:
    line = file2.readline()
    while line:
        line = line.strip()
        if any(re.match(f"^{word}\\b", line) for word in nums):
            outfile.write(line + "\n")
            line = file2.readline()
            if line:
                outfile.write(line)
            else: 
                outfile.write("\n")
                break
        line = file2.readline()

这段代码给了我想要的结果,但是有两个问题:

1) 实际上 file1.txt 和 file2.txt 包含数百万行,并且这段代码完成任务非常慢,即使 file1.txt 被分解以创建多个较小的作业

2) 打印到 out.txt 的输出在作业完成之前是不可见的,因此很难监控进度,如果作业在完成之前中断,那么 out.txt 将为空

是否有另一种更快/更高效的方法来完成这项任务?谢谢!

【问题讨论】:

  • 听起来您需要pandas,然后只需对您的数据执行join

标签: python


【解决方案1】:

关于第一个问题,这行效率低:

if any(re.match(f"^{word}\\b", line) for word in nums)

它会按顺序检查nums 中的每个条目,即使nums 是一个集合。

相反,您可以做这样的事情,只需一步即可完成:

if line.split()[0] in nums:

为了监控进度,您可以调用outfile.flush() 来强制将缓冲区写入磁盘。如果您过于频繁地这样做会降低性能,因此您可能希望保留一个计数器,然后刷新,例如,每千条记录:

i = 0
...
i += 1
if i % 1000 == 0:
    outfile.flush()

【讨论】:

  • 非常感谢,你不会相信我的脚本在这个简单的修复下运行得有多快!
【解决方案2】:

由于您基本上是在进行多次搜索,因此迭代 更有效的方法可能是将整个文件加载到内存中并将其组织到字典中,尽管这显然取决于文件大小。这样,您可以利用 O(1) 的速度访问 dict 键。

一次性加载:

from pathlib import Path

desired_headers = Path('file1.txt').read_text().splitlines()
file_content = Path('file2.txt').read_text().splitlines()

# Based on your example, "keys" were on the even lines (including 0)
# and "values" were on the odd lines. The slicing here separates them
# out using this assumption.
keys, vals = file_content[::2], file_content[1::2]
mapped_content = {
    # Split on whitespace and strip any remaining.
    # Could also just do "x.split('  ')[0]"
    x.split()[0].strip(): {'full_line': x, 'next_line': y} for x, y in zip(keys, vals)
}

然后,您可以直接访问这些行:

>>> for i in desired_headers:
>>>     print(mapped_content[i])

{'full_line': 'ffff  text6', 'next_line': 'some_random_text_F'}
{'full_line': 'aaaa  text1', 'next_line': 'some_random_text_A'}
{'full_line': 'cccc  text3', 'next_line': 'some_random_text_C'}
{'full_line': 'gggg  text7', 'next_line': 'some_random_text_G'}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-09
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    相关资源
    最近更新 更多