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]
...
Спасибо!
Конечно.
for i in range(1, len(a)):
print a[i] - a[i-1]
Я не вижу, что такое настоящая проблема. Вы читали учебник python?
Использование range
прекрасно. Тем не менее, программирование (как математика) о построении на абстракциях. Последовательные пары [(x0, x1), (x1, x2),..., (xn-2, xn-1)], называются парными комбинациями, см., Например, рецепт в документах itertools. Если у вас есть эта функция в вашем наборе инструментов, вы можете написать:
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 = [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
Вот пример из recitpes 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, '')
Я бы порекомендовал использовать удивительную библиотеку more_itertools, она имеет готовую к использованию попарную функцию:
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
, такое поведение считается устаревшим и вызывает DeprecationWarning в Python 3.6. Это не будет работать в Python 3.7 вообще.