【发布时间】:2017-11-02 14:37:59
【问题描述】:
a = [5, 66, 7, 8, 9, ...]
是否可以进行迭代而不是这样写?
a[1] - a[0]
a[2] - a[1]
a[3] - a[2]
a[4] - a[3]
...
谢谢!
【问题讨论】:
-
你在什么时候卡住了?到目前为止你有什么代码?
a = [5, 66, 7, 8, 9, ...]
是否可以进行迭代而不是这样写?
a[1] - a[0]
a[2] - a[1]
a[3] - a[2]
a[4] - a[3]
...
谢谢!
【问题讨论】:
可以使用range。然而,编程(如数学)是建立在抽象之上的。连续对[(x0, x1), (x1, x2), ..., (xn-2, xn-1)],称为成对组合。请参阅itertools docs 中的示例。一旦你的工具集中有了这个函数,你就可以编写:
for x, y in pairwise(xs):
print(y - x)
或用作生成器表达式:
consecutive_diffs = (y - x for (x, y) in pairwise(xs))
【讨论】:
对于 python 2 中的小列表或 python 3 中的任何列表,您可以使用
[x - y for x, y in zip(a[1:], a)]
对于更大的列表,您可能需要
import itertools as it
[x - y for x, y in it.izip(a[1:], a)]
如果你使用的是 python 2
我会考虑把它写成生成器表达式
(x - y for x, y in it.izip(a[1:], a))
这将避免一次在内存中创建第二个列表,但您只能对其进行一次迭代。如果您只想要对其进行一次迭代,那么这是理想的,并且如果您稍后决定需要随机或重复访问,则很容易更改。特别是如果您要进一步处理它以制作列表,那么最后一个选项是理想的。
更新:
目前最快的方法是
import itertools as it
import operator as op
list(it.starmap(op.sub, it.izip(a[1:], a)))
$ python -mtimeit -s's = [1, 2]*10000' '[x - y for x, y in zip(s[1:], s)]'
100 loops, best of 3: 13.5 msec per loop
$ python -mtimeit -s'import itertools as it; s = [1, 2]*10000' '[x - y for x, y in it.izip(s[1:], s)]'
100 loops, best of 3: 8.4 msec per loop
$ python -mtimeit -s'import itertools as it; import operator as op; s = [1, 2]*10000' 'list(it.starmap(op.sub, it.izip(s[1:], s)))'
100 loops, best of 3: 6.38 msec per loop
【讨论】:
pypy -mtimeit -s'import itertools;import operator; seq=[0,1]*10000' '[seq[i+1] - seq[i] for i in range(len(seq)-1)]'
我建议使用很棒的more_itertools 库,它有现成的pairwise function:
import more_itertools
for a, b in more_itertools.pairwise([1, 2, 3, 4, 5]):
print(a, b)
# 1 2
# 2 3
# 3 4
# 4 5
这将使您免于编写自己的(可能是错误的)实现。例如,此页面上的大多数实现都不能正确处理空迭代的情况——生成器函数永远不应该引发StopIteration,这种行为considered deprecated 并导致 Python 3.6 中的 DeprecationWarning。它根本不适用于 Python 3.7。
【讨论】:
pairwise function 已添加到标准库的一部分 itertools。
这是来自 itertools 食谱的示例:
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
这不是很可读。如果你喜欢更容易理解的东西 了解生成器是如何工作的,这里有一个更长的例子,结果相同:
def pairwise(it):
"""
Walk a list in overlapping pairs.
>>> list(pairwise([0, 1, 2, 3, 4, 5]))
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
"""
it = iter(it)
start = None
while True:
if not start:
start = next(it)
end = next(it)
yield start, end
start = end
【讨论】:
【讨论】:
def pairwise(iterable):
i = iter(iterable)
while True:
yield next(i), next(i, '')
【讨论】:
[1, 2, 3, 4, 5, 6],这会产生[(1, 2), (3, 4), (5, 6)]。这个问题想要更接近[(1, 2), (2, 3), (3, 4), ...]。