检查两个生成器的不同之处
Check where two generators are different
假设我有两个生成器,为简单起见:
it1 = iter([1,2,3,4])
it2 = iter([1,2,10,20])
了解第一个差异(位置 2)在哪里或它们是否相等的最佳方法是什么?我想避免显式循环:
for pos, v1, v2 in enumerate(izip(it1, it2)):
if v1 != v2: return pos
return None
并使用函数式编程:
try:
return next(pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2)
except StopIteration:
return None
关键是我使用的解决方案很丑陋,比显式循环更冗长,...
你能做得更好吗?
您可以通过为 next
:
提供默认值来简化第二个示例
return next((pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2), None)
来自docs:
next(iterator[, default])
Retrieve the next item from the iterator
by calling its __next__()
method. If default
is given, it is returned if the iterator is
exhausted, otherwise StopIteration
is raised.
作为替代答案,您可以使用 numpy.where
代替遍历数组并使用 enumerate
:
>>> import numpy as np
>>> def test(a,b):
... try :
... return np.where(a!=b)[0][0]
... except IndexError:
... return None
...
>>> test(it1,it2)
>>> it1 = np.array([1,2,3,4])
>>> it2 = np.array([1,2,0,4])
>>> test(it1,it2)
2
或 next
:
>>> it1 = np.array([1,2,3,4,6])
>>> it2 = np.array([1,2,3,0,6])
>>> next(iter(np.where(it1!=it2)[0]),None)
3
同样对于 generators
,您可以使用 numpy.fromiter
将生成器转换为 numpy 数组!
一些基准测试:
:~$ python -m timeit "from itertools import izip;it1=[1,2,3,4];it2=[1,2,10,20];next((pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2), None)"
100000 loops, best of 3: 2.77 usec per loop
:~$ python -m timeit "import numpy as np;it1=[1,2,3,4];it2=[1,2,10,20];next(iter(np.where(it1!=it2)[0]),None)"
100000 loops, best of 3: 2.02 usec per loop
我一直在尝试内置 filter but probably python3 filterfalse 可能会更好。
filter(lambda x: x if len(set(x)) else None, zip(it1, it2))
>>> [(3, 10), (4, 20)]
但是,我们没有得到差异索引,而只是以这种方式得到不同的项目。
所以我一直在考虑更多并检查 related 但实际上,OP 想要索引而不是结果。所以,修改
filter(lambda x:x[0] if len(set(x[1])) > 1 else None, enumerate(zip(it1,it2)))
>>> [(2, (3, 10)), (3, (4, 20))]
当然,这与上面的答案还差得很远,所以我不建议在生产代码中这样做。只有利益?没有进口。这是我的时间结果:
python -m timeit "import numpy as np;it1=[1,2,3,4];it2=[1,2,10,20];next(iter(np.where(it1!=it2)[0]),None)"
100000 loops, best of 3: 2.02 usec per loop
10 loops, best of 3: 13.1 usec per loop
python -m timeit "from itertools import izip;it1=[1,2,3,4];it2=[1,2,10,20];next((pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2), None)"
100000 loops, best of 3: 16.6 usec per loop
python -m timeit "it1=[1,2,3,4];it2=[1,2,10,20];filter(lambda x:x[0] if len(set(x[1])) > 1 else None, enumerate(zip(it1,it2)))"
10000 loops, best of 3: 19.1 usec per loop
假设我有两个生成器,为简单起见:
it1 = iter([1,2,3,4])
it2 = iter([1,2,10,20])
了解第一个差异(位置 2)在哪里或它们是否相等的最佳方法是什么?我想避免显式循环:
for pos, v1, v2 in enumerate(izip(it1, it2)):
if v1 != v2: return pos
return None
并使用函数式编程:
try:
return next(pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2)
except StopIteration:
return None
关键是我使用的解决方案很丑陋,比显式循环更冗长,...
你能做得更好吗?
您可以通过为 next
:
return next((pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2), None)
来自docs:
next(iterator[, default])
Retrieve the next item from the
iterator
by calling its__next__()
method. Ifdefault
is given, it is returned if the iterator is exhausted, otherwiseStopIteration
is raised.
作为替代答案,您可以使用 numpy.where
代替遍历数组并使用 enumerate
:
>>> import numpy as np
>>> def test(a,b):
... try :
... return np.where(a!=b)[0][0]
... except IndexError:
... return None
...
>>> test(it1,it2)
>>> it1 = np.array([1,2,3,4])
>>> it2 = np.array([1,2,0,4])
>>> test(it1,it2)
2
或 next
:
>>> it1 = np.array([1,2,3,4,6])
>>> it2 = np.array([1,2,3,0,6])
>>> next(iter(np.where(it1!=it2)[0]),None)
3
同样对于 generators
,您可以使用 numpy.fromiter
将生成器转换为 numpy 数组!
一些基准测试:
:~$ python -m timeit "from itertools import izip;it1=[1,2,3,4];it2=[1,2,10,20];next((pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2), None)"
100000 loops, best of 3: 2.77 usec per loop
:~$ python -m timeit "import numpy as np;it1=[1,2,3,4];it2=[1,2,10,20];next(iter(np.where(it1!=it2)[0]),None)"
100000 loops, best of 3: 2.02 usec per loop
我一直在尝试内置 filter but probably python3 filterfalse 可能会更好。
filter(lambda x: x if len(set(x)) else None, zip(it1, it2))
>>> [(3, 10), (4, 20)]
但是,我们没有得到差异索引,而只是以这种方式得到不同的项目。
所以我一直在考虑更多并检查 related 但实际上,OP 想要索引而不是结果。所以,修改
filter(lambda x:x[0] if len(set(x[1])) > 1 else None, enumerate(zip(it1,it2)))
>>> [(2, (3, 10)), (3, (4, 20))]
当然,这与上面的答案还差得很远,所以我不建议在生产代码中这样做。只有利益?没有进口。这是我的时间结果:
python -m timeit "import numpy as np;it1=[1,2,3,4];it2=[1,2,10,20];next(iter(np.where(it1!=it2)[0]),None)"
100000 loops, best of 3: 2.02 usec per loop
10 loops, best of 3: 13.1 usec per loop
python -m timeit "from itertools import izip;it1=[1,2,3,4];it2=[1,2,10,20];next((pos for pos, (v1, v2) in enumerate(izip(it1, it2)) if v1 != v2), None)"
100000 loops, best of 3: 16.6 usec per loop
python -m timeit "it1=[1,2,3,4];it2=[1,2,10,20];filter(lambda x:x[0] if len(set(x[1])) > 1 else None, enumerate(zip(it1,it2)))"
10000 loops, best of 3: 19.1 usec per loop