Нахождение различий между элементами списка - PullRequest
94 голосов
/ 08 марта 2010

Учитывая список чисел, как найти различия между каждым (i) -ым и (i+1) -ым из его элементов? Лучше использовать lambda или, возможно, понимание списка?

Пример:
Учитывая список t=[1,3,6,...], он должен найти список v=[2,3,...], потому что 3-1=2, 6-3=3 и т. Д.

Ответы [ 8 ]

125 голосов
/ 08 марта 2010
>>> t
[1, 3, 6]
>>> [j-i for i, j in zip(t[:-1], t[1:])]  # or use itertools.izip in py2k
[2, 3]
94 голосов
/ 08 марта 2010

Другие ответы верны, но если вы выполняете числовую работу, вы можете подумать, что Numpy Используя numpy, ответ:

v = numpy.diff(t)
32 голосов
/ 23 мая 2013

Если вы не хотите использовать numpy или zip, вы можете использовать следующее решение:

>>> t = [1, 3, 6]
>>> v = [t[i+1]-t[i] for i in range(len(t)-1)]
>>> v
[2, 3]
10 голосов
/ 22 июля 2014

Вы можете использовать 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.
  • Доступ к отдельным элементам по индексу очень медленный, потому что каждый доступ к индексу - это вызов метода в python
  • 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
    
3 голосов
/ 23 октября 2017

Функциональный подход:

>>> 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]
3 голосов
/ 08 марта 2010

Хорошо.Я думаю, что нашел правильное решение:

v = [x[1]-x[0] for x in zip(t[1:],t[:-1])]
0 голосов
/ 05 июня 2019

Я бы предложил использовать

v = np.diff(t)

это просто и легко читается.

Но если вы хотите, чтобы v имела ту же строку, что и t, тогда

v = np.diff(t[0] + t)

или

v = np.diff(t + t[-1])

К вашему сведению: это будет работать только для списков.

для массивов NumPy

v = np.diff(np.append(t[0], t))
0 голосов
/ 15 апреля 2016

Мой путь

>>>v = [1,2,3,4,5]
>>>[v[i] - v[i-1] for i, value in enumerate(v[1:], 1)]
[1, 1, 1, 1]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...