如何检测两个Python迭代器产生相同的项?

时间:2014-08-09 08:01:01

标签: python python-2.7 iterator compare

是否有一种简洁且内存有效的方法来确定两个迭代器lines1lines2是否产生相同的项目?

例如,这些迭代器可以是从文件对象中检索的行:

with io.open(`some.txt`, 'r', encoding='...') as lines1:
  with io.open(`other.txt`, 'r', encoding='...') as lines2:
    lines_are_equal = ...

直观地可以预料到

lines_are_equal = lines1 == lines2  # DOES NOT WORK

会给出理想的结果。但是,这将永远是False,因为它只比较迭代器的地址而不是产生的项目。

如果内存不是问题,可以将迭代器转换为列表并进行比较:

lines_are_equal = list(lines1) == list(lines2)  # works but uses a lot of memory

我已经检查了itertools,希望找到类似

的内容
lines_are_equal = itertools.equal(lines1, lines2)  # DOES NOT WORK

但似乎没有任何类似的功能。

到目前为止我能做的最好的事情是使用itertools.zip_longest()(Python 2:izip_longest())循环遍历这两个迭代器:

lines_are_equal = True
for line1, line2 in itertools.zip_longest(lines1, lines2):
  if line1 != line2:
    lines_are_equal = False
    break

这确实给出了理想的结果,并且记忆效率高但是感觉笨拙和单声道。

有更好的方法吗?

解决方案:应用注释中的集体智慧并回答这是一行帮助函数,即使两个迭代器相同或者可以具有尾随None值,它也可以工作: / p>

def iter_equal(items1, items2):
  '''`True` if iterators `items1` and `items2` contain equal items.'''
  return (items1 is items2) or \
          all(a == b for a, b in itertools.zip_longest(items1, items2, fillvalue=object()))

您仍然需要确保迭代器彼此没有副作用。

1 个答案:

答案 0 :(得分:3)

如何将all与生成器表达式一起使用:

lines_are_equal = all(a == b for a, b in itertools.zip_longest(lines1, lines2))

更新如果iterable可以产生尾随None,则最好将fillvalue=object()指定为user2357112评论。 (默认情况下,None用于填充值)

lines_are_equal = all(a == b for a, b in
                      itertools.zip_longest(lines1, lines2, fillvalue=object()))

如果您的目的是比较两个文件,而不是任何可迭代的文件,则可以使用filecmp.cmp代替:

files_are_equal = filecmp.cmp(filename1, filename2)