是否有一种简洁且内存有效的方法来确定两个迭代器lines1
和lines2
是否产生相同的项目?
例如,这些迭代器可以是从文件对象中检索的行:
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()))
您仍然需要确保迭代器彼此没有副作用。
答案 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)