繁体   English   中英

如何检查列表中一行的任何部分是否包含另一个列表的整行? PYTHON

[英]How can I check if any part of a line from a list contains the full line of another list? PYTHON

我试图找到正确的代码并自己编写了多次尝试,但我希望这里有人可以提供帮助。

我有一个小文件和一个大文件: 小:90,000 行 大:1,200,000 行

如果大文件中的该行包含小文件中的任何行,我正在尝试将大文件中的任何行打印到结果文件。 另外我应该添加小写,因为这无关紧要。

示例:大文件行: '{"data": "SN@StackOverflow"}'

小文件行 (ANY): '@stackoVerfloW' -> 打印大行。

这应该将大行打印到结果文件中。 请注意,小文件行将是较大文件行的子集。 这是我的目标,因为我不是在寻找匹配的行,而是在寻找包含来自小文件的数据的行,然后将这些大文件行保存为结果。

我尝试使用嵌套的 for 循环来执行此操作,但是它没有打印任何结果。 此外,我将文件作为列表加载,希望减少时间,因为这些行将存储在 memory 中。 我也无法对这些行进行排序,因为这些行不统一。

results = open("results.txt", "w")

small = []
large = []


for line in open('small.txt'):
    small.append(line)
    
for line in open('large.txt'):
    large.append(line)
    
for j in large:
    for i in small:
        if i in j:
            results.write(j + '\n')

如果有什么我可以做的来澄清我的问题,请告诉我,对不起,这是我的第一篇文章,我希望将来能写出更好的问题。

无需同时将所有大文件读入 memory。 在进行in测试之前,您几乎肯定还想从小文件的行中去除换行符(您可以为此使用strip来去除任何前导和尾随空格)。

查看您的示例字符串,您似乎还需要进行不区分大小写的比较,因此在比较它们之前在此处使用lower()将两者都转换为小写。

即使小文件中有多行与之匹配,您也可能只编写每个 output 行一次,因此break 另请注意,如果您没有从大文件的输入行中删除它,则不需要编写额外的换行符。

把这些放在一起会得到这样的东西。

small = []

with open('small.txt') as f:
    for line in f:
        small.append(line.strip().lower())

with open('results.txt', 'w') as fout:
    with open('large.txt') as fin:
        for line in fin:
            for i in small:
                if i in line.lower():
                    fout.write(line)
                    break  # breaks from inner loop only (for i in small)

您还可以通过执行以下操作来简化“文件到行列表”步骤:

small = open('small.txt', 'r').readlines()
large = open('large.txt', 'r').readlines()

然后迭代如下:

with open("results.txt", "w") as results:
    for j in large:
        for i in small:
            if i.lower() in j.lower():
                results.write(j)

祝你好运

但是可能存在问题 - 正如您所说的那样,尝试将所有 90000 行与另一个文件上的 1,200,000 行中的每一行进行匹配的天真方法,即使在那个时候,执行一个“包含”(Python in )运算符大文件行,将导致高昂的处理成本。 您基本上是在谈论 M x N x O 操作,M 是大文件大小,N 是小文件,O 是大文件中的平均行长(减去小文件中的平均行长) - 这些是从 1 万亿次操作开始 - 计算机在 GHz 范围内运行,如果小文件可以放入 memory,则可能在几个小时内可行。

一个更聪明的选择是对大文件中的每一行使用与位置无关的哈希。 与位置无关的散列可能很复杂 - 但较宽行中所有可能的单词子集的一些散列可以在恒定时间 O(1) 内与包含较小文件中所有 90.000 行的字典匹配 - 对每个1,200,000 行可以在线性时间内完成 - 只需使用字符串规范化和 python 字典,将搜索从几小时或几天减少到几秒钟。

最后,这应该是所有需要的代码:

import re

def normalize(text):
    text = text.strip().lower()
    # strip punctuation
    text = re.sub('[^\w\ \d]', ' ', text)
    words = tuple(text.split())
    return words

def normalized_subsets(text):
    words = normalize(text)
    combinations = set()
    for i in range(len(words)):
        for j in range(i + 1, len(words) + 1):
            combinations.add(words[i: j])
    return combinations


def main():
    small = {normalize(line): linenum for
             linenum, line in enumerate(open("small.txt")) if line.strip()}
    with open("large.txt") as large,  open("results.txt", "w") as results:
        for line_num, line in large:
            for combination in combinations(line):
                if combination in small:
                    results.write(f"{linenum} {small[combination]} {line}")

main()

因此,虽然您仍然在此代码中看到嵌套for循环,但嵌套版本仅循环遍历每行中可能的单词子集 - 对于 30 个单词的行,这将少于 500 个组合 - 我们进行 500 次比较以匹配任何90000 个较小的文件字典中的这些单词子组,而不是 90.000 个比较。

所以,它最终仍然是一个二次算法,但应该更快 - (对于问题中的示例行,删除标点符号后,它将尝试匹配中的每个元素

{('data',),
 ('data', 'sn'),
 ('data', 'sn', 'stackoverflow'),
 ('sn',),
 ('sn', 'stackoverflow'),
 ('stackoverflow',)}

这只是 6 次比较(在 90000 行中进行线性搜索)

(为了获得更大的价值,此代码还在结果文件中匹配行开头的大文件和较小文件中记录行号)

如果您的样本数据表示您正在使用的实际数据,则可以像比较它们的小写一样简单:

# ... your I/O code

for j in large:
    for i in small:
        if i.lower() in j.lower():
            results.write(j + '\n')

请注意.lower()调用,这是我对您的代码所做的唯一修改。

如果这仍然不起作用,请从每个文件中再发布几行以帮助我们评估。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM