是否有一种简洁且节省内存的方法来确定两个迭代器 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
这确实给出了所需的结果,并且内存效率高,但感觉笨拙且不符合Python风格。
有更好的方法吗?
解决方案:应用评论中的集体智慧并回答这是一个单行辅助函数,即使两个迭代器相同或可以有尾随 None
值:
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()))
您仍然必须确保迭代器不会相互产生副作用。
最佳答案
使用 all
怎么样?使用生成器表达式:
lines_are_equal = all(a == b for a, b in itertools.zip_longest(lines1, lines2))
UPDATE 如果 iterable 可以生成尾随 None
,则最好按照 user2357112 的评论指定 fillvalue=object()
。 (默认情况下,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)
关于python - 如何检测两个Python迭代器产生相同的项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25216504/