목록 요소 간의 차이점 찾기


113

숫자 목록이 주어지면 모든 ( i) 번째 요소와 ( ) 번째 요소의 차이점을 어떻게 찾을 수 i+1있습니까?

lambda표현이나 목록 이해 를 사용하는 것이 더 낫 습니까?

예를 들면 :

목록을 감안할 때 t=[1,3,6,...], 목표는 목록을 찾을 것입니다 v=[2,3,...]때문에 3-1=2, 6-3=3

답변:


154
>>> t
[1, 3, 6]
>>> [j-i for i, j in zip(t[:-1], t[1:])]  # or use itertools.izip in py2k
[2, 3]

14
절대적인 차이가 필요한 경우 [abs(j-i) for i,j in zip(t, t[1:])]
Anil

더 효율적으로 만들고 싶은 경우 : list(itertools.starmap(operator.sub, zip(t[1:], t)))(가져온 후 itertoolsoperator).
blhsing

3
실제로는 간단 list(map(operator.sub, t[1:], t[:-1]))합니다.
blhsing

훌륭한! 나는이 대답을 매우 좋아합니다!
Chayim Friedman

104

다른 답변은 정확하지만 수치 작업을 수행하는 경우 numpy를 고려할 수 있습니다. numpy를 사용하면 대답은 다음과 같습니다.

v = numpy.diff(t)

매우 유용합니다! 감사! np.diff([2,4,9])[2,5]
TravelTrader

이것이 zip버전 보다 더 효율적 일까요?
user760900

35

numpy또는 을 사용하지 않으려면 zip다음 솔루션을 사용할 수 있습니다.

>>> t = [1, 3, 6]
>>> v = [t[i+1]-t[i] for i in range(len(t)-1)]
>>> v
[2, 3]

12

itertools.teezip을 사용 하여 결과를 효율적으로 작성할 수 있습니다.

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이다 느린 가 먼저 변환해야하기 때문에 listA를 ndarray. 당신이 경우 분명히 시작ndarray이 될 것입니다 훨씬 더 빨리 :

    In [22]: arr = np.array(L)
    
    In [23]: %timeit np.diff(arr)
    100 loops, best of 3: 3.02 ms per loop

두 번째 솔루션으로, islice(seq, 1, None)대신 islice(seq, 1, len(seq))차종은 무한 반복 가능 객체와 함께 작동
브라만 스나이더

5

:=Python 3.8 이상에서 사용할 수 있는 해마 연산자 사용 :

>>> t = [1, 3, 6]
>>> prev = t[0]; [-prev + (prev := x) for x in t[1:]]
[2, 3]

5

나는 사용하는 것이 좋습니다

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))

좋은 대답, 같은 길이를 보장하기 위해 prepend 키워드를 사용할 수도 있습니다. 아래 대답을 참조하십시오. 조금 더 깔끔하다고 생각합니다
Adrian Tompkins

4

기능적 접근 :

>>> 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]

운영자 방법은 멋지고 우아한
bcattle

3

확인. 적절한 해결책을 찾은 것 같습니다.

v = [x[1]-x[0] for x in zip(t[1:],t[:-1])]

2
그래도 좋지만, 정렬 된 목록의 경우 zip (t [1 :], t [:-1])]에서 x에 대해 v = [x [0] -x [1]이어야한다고 생각합니다!
Amit Karnik

0

주기적 경계가있는 솔루션

때로는 수치 적분을 사용하여 주기적 경계 조건이있는 목록을 구분하고 싶을 것입니다 (따라서 첫 번째 요소가 마지막 요소와의 차이를 계산합니다.이 경우 numpy.roll 함수가 유용합니다.)

v-np.roll(v,1)

0이 추가 된 솔루션

(완벽 함을 위해) 또 다른 numpy 솔루션은

numpy.ediff1d(v)

이것은 numpy.diff로 작동하지만 벡터에서만 작동합니다 (입력 배열을 평평하게합니다). 결과 벡터 앞에 숫자를 추가하거나 추가하는 기능을 제공합니다. 이것은 첫 번째 항목을 건드리지 않은 상태에서 입력 변수와 동일한 길이의 결과 목록을 원하기 때문에 기상 변수 (예 : 비, 잠열 등)에서 종종 플럭스 인 누적 된 필드를 처리 할 때 유용합니다.

그럼 당신은 쓸 것입니다

np.ediff1d(v,to_begin=v[0])

물론, np.diff 명령으로도이 작업을 수행 할 수 있습니다.이 경우에는 prepend 키워드를 사용하여 시리즈 앞에 0을 추가해야합니다.

np.diff(v,prepend=0.0) 

위의 모든 솔루션은 입력 값과 길이가 같은 벡터를 반환합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.