Ответ 1
>>> t
[1, 3, 6]
>>> [j-i for i, j in zip(t[:-1], t[1:])] # or use itertools.izip in py2k
[2, 3]
Учитывая список чисел, как найти различия между каждым (i
) -th элементом и его (i+1
) -th?
Лучше использовать выражение lambda
или, возможно, понимание списка?
Например:
Учитывая список t=[1,3,6,...]
, цель состоит в том, чтобы найти список v=[2,3,...]
, потому что 3-1=2
, 6-3=3
и т.д.
>>> t
[1, 3, 6]
>>> [j-i for i, j in zip(t[:-1], t[1:])] # or use itertools.izip in py2k
[2, 3]
Другие ответы верны, но если вы выполняете численную работу, вы можете рассмотреть numpy. Используя numpy, ответ:
v = numpy.diff(t)
Если вы не хотите использовать numpy
или zip
, вы можете использовать следующее решение:
>>> t = [1, 3, 6]
>>> v = [t[i+1]-t[i] for i in range(len(t)-1)]
>>> v
[2, 3]
Вы можете использовать itertools.tee
и zip
для эффективного построения результата:
from itertools import tee
# python2 only:
#from itertools import izip as zip
def differences(seq):
iterable, copied = tee(seq)
next(copied)
for x, y in zip(iterable, copied):
yield y - x
Или используя вместо этого itertools.islice
:
from itertools import islice
def differences(seq):
nexts = islice(seq, 1, None)
for x, y in zip(seq, nexts):
yield y - x
Вы также можете избежать использования модуля itertools
:
def differences(seq):
iterable = iter(seq)
prev = next(iterable)
for element in iterable:
yield element - prev
prev = element
Все эти решения работают в постоянном пространстве, если вам не нужно хранить все результаты и поддерживать бесконечные итерации.
Вот некоторые микро-тесты решений:
In [12]: L = range(10**6)
In [13]: from collections import deque
In [15]: %timeit deque(differences_tee(L), maxlen=0)
10 loops, best of 3: 122 ms per loop
In [16]: %timeit deque(differences_islice(L), maxlen=0)
10 loops, best of 3: 127 ms per loop
In [17]: %timeit deque(differences_no_it(L), maxlen=0)
10 loops, best of 3: 89.9 ms per loop
И другие предлагаемые решения:
In [18]: %timeit [x[1] - x[0] for x in zip(L[1:], L)]
10 loops, best of 3: 163 ms per loop
In [19]: %timeit [L[i+1]-L[i] for i in range(len(L)-1)]
1 loops, best of 3: 395 ms per loop
In [20]: import numpy as np
In [21]: %timeit np.diff(L)
1 loops, best of 3: 479 ms per loop
In [35]: %%timeit
...: res = []
...: for i in range(len(L) - 1):
...: res.append(L[i+1] - L[i])
...:
1 loops, best of 3: 234 ms per loop
Обратите внимание, что:
zip(L[1:], L)
эквивалентен zip(L[1:], L[:-1])
поскольку zip
уже заканчивается на самом коротком входе, однако он избегает полной копии L
numpy.diff
медленный, потому что он должен сначала преобразовать list
в ndarray
. Очевидно, что если вы начнете с ndarray
это будет намного быстрее:
In [22]: arr = np.array(L)
In [23]: %timeit np.diff(arr)
100 loops, best of 3: 3.02 ms per loop
Ok. Думаю, я нашел правильное решение:
v = [x[1]-x[0] for x in zip(t[1:],t[:-1])]
Функциональный подход:
>>> import operator
>>> a = [1,3,5,7,11,13,17,21]
>>> map(operator.sub, a[1:], a[:-1])
[2, 2, 2, 4, 2, 4, 4]
Использование генератора:
>>> import operator, itertools
>>> g1,g2 = itertools.tee((x*x for x in xrange(5)),2)
>>> list(itertools.imap(operator.sub, itertools.islice(g1,1,None), g2))
[1, 3, 5, 7]
Использование индексов:
>>> [a[i+1]-a[i] for i in xrange(len(a)-1)]
[2, 2, 2, 4, 2, 4, 4]
Я бы предложил использовать
v = np.diff(t)
это просто и легко читается.
Но если вы хотите, чтобы v
имела ту же строку, что и t
тогда
v = np.diff([t[0]] + t) # for python 3.x
или же
v = np.diff(t + [t[-1]])
К вашему сведению: это будет работать только для списков.
для массивов NumPy
v = np.diff(np.append(t[0], t))
Мой путь
>>>v = [1,2,3,4,5]
>>>[v[i] - v[i-1] for i, value in enumerate(v[1:], 1)]
[1, 1, 1, 1]