Pytanie Python - Różnice między elementami listy


Biorąc pod uwagę listę numerów, jak znaleźć różnice między każdym (i) -ty i (i+1) -th z jego elementów? Czy lepiej użyć lambda, a może list rozumieć?

Przykład: Biorąc pod uwagę listę t=[1,3,6,...] to jest znaleźć listę v=[2,3,...] bo 3-1=2, 6-3=3itp.


76
2018-03-08 11:16


pochodzenie




Odpowiedzi:


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

107
2018-03-08 11:23



Jeśli potrzebujesz absolutnych różnic, [abs(j-i) for i,j in zip(t, t[1:])] - Anil
Jeśli chcesz, aby był bardziej wydajny: list(itertools.starmap(operator.sub, zip(t[1:], t))) (po zaimportowaniu itertools i operator). - blhsing
Właściwie po prostu list(map(operator.sub, t[1:], t[:-1])) zrobi. - blhsing


Pozostałe odpowiedzi są poprawne, ale jeśli wykonujesz pracę numeryczną, możesz rozważyć numpy. Używając numpy, odpowiedź brzmi:

v = numpy.diff(t)

72
2018-03-08 14:26





Jeśli nie chcesz używać numpy ani zipmożesz użyć prostego (najprościej moim zdaniem) rozwiązania:

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

25
2018-05-23 12:51





Możesz użyć itertools.tee i zip efektywnie zbudować wynik:

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

Lub za pomocą itertools.islice zamiast:

from itertools import islice

def differences(seq):
    nexts = islice(seq, 1, None)
    for x, y in zip(seq, nexts):
        yield y - x

Możesz także uniknąć używania itertools moduł:

def differences(seq):
    iterable = iter(seq)
    prev = next(iterable)
    for element in iterable:
        yield element - prev
        prev = element

Wszystkie te rozwiązania działają w stałej przestrzeni, jeśli nie trzeba przechowywać wszystkich wyników i obsługiwać nieskończonych iterables.


Oto kilka mikro-benchmarków rozwiązań:

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

Inne proponowane rozwiązania:

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

Uwaga:

  • zip(L[1:], L) jest równa zip(L[1:], L[:-1]) od zip kończy się na najkrótszym wprowadzeniu, jednak unika całej kopii L.
  • Dostęp do pojedynczych elementów według indeksu to bardzo wolno, ponieważ każdy dostęp do indeksu jest wywołaniem metody w pythonie
  • numpy.diff jest powolny ponieważ musi najpierw przekonwertować list do a ndarray. Oczywiście, jeśli ty początek z ndarray To będzie dużo szybciej:

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

8
2017-07-22 17:34



w drugim rozwiązaniu islice(seq, 1, None) zamiast islice(seq, 1, len(seq)) sprawia, że ​​działa z nieskończonymi iterables - braham-snyder
@ braham-snyder Masz rację. Naprawione. Dzięki - Bakuriu


Ok. Myślę, że znalazłem właściwe rozwiązanie:

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

3
2018-03-08 11:25



ya good, ale myślę, że powinno to być v = [x [0] -x [1] dla x w zip (t [1:], t [: - 1])] dla posortowanej listy! - Amit Karnik


Podejście funkcjonalne:

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

Korzystanie z generatora:

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

Korzystanie z indeksów:

>>> [a[i+1]-a[i] for i in xrange(len(a)-1)]
[2, 2, 2, 4, 2, 4, 4]

3
2017-10-23 12:36



Metoda operatora jest przyjemna i elegancka - bcattle


Moja droga

>>>v = [1,2,3,4,5]
>>>[v[i] - v[i-1] for i, value in enumerate(v[1:], 1)]
[1, 1, 1, 1]

-1
2018-04-15 07:09



Za pomocą enumerate jest marnotrawstwem, ponieważ nie używasz value. Widzieć stackoverflow.com/a/16714453/832230 - A-B-B