For/if 状态以一种方式工作,但不以另一种方式工作

For/if state works one way, but not the other

我通常讨厌寻求帮助,但在这方面我已经受够了。

当我执行以下操作时,该函数起作用并提供所需的输出(文件之间的匹配行)。如果我反转 for/if 语句正在使用的文件,我不会得到文件之间匹配的行。因此,它以一种方式而不是另一种方式从两个文件中提取所需的(相同的)文本。

作品:

 with open('textfile1.txt','r') as t1, open('textfile2.txt', 'r') as t2:
     for line in t1:
         if line in t2:
             print(line)

无效:

 with open('textfile1.txt','r') as t1, open('textfile2.txt', 'r') as t2:
      for line in t2:
         if line in t1:
            print(line)

我确定这很简单,但我真的盯着它看的时间比我想说的要长。这是一小段代码,我正试图为我正在从事的一个更大的项目工作。我似乎无法解决这个具体问题。

解决方案:

 with open('textfile1.txt','r') as t1, open('textfile2.txt', 'r') as t2:
      t1_lines = set(t1)  
      for line in t2:
         if line in t1_lines:
            print(line)

遍历一次后迭代器就用完了。 t1t2 是迭代器。每次迭代都会生成一行文件。

if line in t2 遍历 t2 直到找到匹配项。如果找不到匹配项,t2 将完全耗尽。所以下次测试if line in t2时,即使linetextfile2.txt.

中也找不到匹配项

例如,假设 textfile1.txt 包含

BAR
BAZ

textfile2.txt包含

FOO
BAR 

然后考虑

with open('textfile1.txt','r') as t1, open('textfile2.txt', 'r') as t2:
     for line in t2:
        if line in t1:
           print(line)

在第一次通过循环时,line'FOO'(这里让我们忽略行尾字符)。 if line in t1 导致 t1 遍历 BARBAZ。由于 line 不等于其中任何一个,因此 t1 已用完并且循环继续下一个值。

在第二遍中,line 等于 BAR。现在 if line in t1 测试 BAR 是否在空迭代器中。所以没有一行被打印出来。


相比之下,当运行

with open('textfile1.txt','r') as t1, open('textfile2.txt', 'r') as t2:
    for line in t1:
        if line in t2:
            print(line)

在第一次通过循环时,lineBAR。现在 if line in t2 为 True,因为 t2 将产生行 BAR

您不能在文件上使用 in 并让它工作两次。

发生的事情是 in 将文件 reader 位置向前移动 。文件对象是一个 iterable 并且 in 在这样的对象上获取每个对象(在这种情况下来自文件的行)来测试一个是否相等。当您找到一个相等的对象时,迭代停止并返回 True。如果没有找到相等的对象,迭代将继续,直到到达终点。

例如,如果 t2 只包含 一个额外的行 ,那么试图在 t1 中找到该行将导致所有 t1 阅读以尝试找到它。从 t2 读取的任何后续行现在都将失败,因为 t1 已到达末尾并且不会返回更多行。

在此过程中,可迭代的任何时候都不会 'rewound' 开始。文件读指针只向前移动,不会回到起点。

如果使用 in 在一种情况下有效,那么这意味着从 t1 读取的每一行也恰好以相同的顺序 出现在t2。反之则不然,如果 t2 包含 额外的行 ,这些行在第一个文件中以不同的顺序出现。

如果您的文件很小,将其中一个文件放入 set object:

with open('textfile1.txt','r') as t1, open('textfile2.txt', 'r') as t2:
    t1_lines = set(t1)
    for line in t2:
         if line in t1_lines:
             print(line)

集合让您可以在 恒定时间 中测试对象的存在;无论 t1 中有多少行,平均而言,测试其中一行所花费的时间总是相同的。

如果您使用 文件,您可以使用 fileobj.seek(0) 强制文件指针回到开头。但是,跨文件读取(扫描 in 测试时会到达每一行)将会 。您可以使用 memory mapping 来稍微缓解这种情况,但您可能希望确保文件行已排序,然后使用索引或二分法来加快查找匹配行的过程。