2010-03-08 17 views
66

Dato un elenco di numeri come trovare le differenze tra ogni (i) -th e (i+1) -th dei suoi elementi? Si dovrebbe usare meglio lambda o forse liste di comprensione?Python - Differenze tra gli elementi di un elenco

Esempio: Dato un elenco t=[1,3,6,...] è quello di trovare un elenco v=[2,3,...] perché 3-1=2, 6-3=3, ecc

risposta

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

in caso di necessità differenze assolute, '[ABS (ji) per i, j a zip (t, t [1:])]' – Anil

3

Ok. Penso di aver trovato la soluzione corretta:

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

ya la sua buona , ma penso che avrebbe dovuto essere v = [x [0] -x [1] per x in zip (t [1:], t [: - 1])] per la lista ordinata! –

67

Le altre risposte sono corrette ma se si sta facendo un lavoro numerico, si potrebbe voler considerare numpy. Utilizzando numpy, la risposta è:

v = numpy.diff(t) 
23

Se non si desidera utilizzare numpyzip, è possibile utilizzare la semplice (semplice a mio parere) soluzione:

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

È possibile utilizzare itertools.tee e zip per costruire in modo efficiente il risultato:

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 

o utilizzando itertools.islice invece:

012.
from itertools import islice 

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

Si può anche evitare di usare il modulo itertools:

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

Tutti questi lavori soluzione nello spazio costante se non è necessario per memorizzare tutti i risultati. La prima e l'ultima soluzione funzionano anche con infiniti iterables, mentre la seconda richiede una sequenza finita come input.


Ecco alcuni micro-benchmark delle soluzioni:

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 

E le altre soluzioni proposte:

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 

notare che:

  • zip(L[1:], L) è equivalente a zip(L[1:], L[:-1]) poiché zip termina già con l'input più breve, tuttavia evita l'intera copia di L.
  • accesso ai singoli elementi da indice è molto lento perché ogni accesso indice è una chiamata di metodo in pitone
  • numpy.diff è lento perché deve prima convertire il list ad un ndarray.Ovviamente se si inizia con una ndarray sarà molto più veloce:

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

Il mio modo

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

Usare 'enumerate' è dispendioso perché non stai usando' value'. Vedi https://stackoverflow.com/a/16714453/832230 –

2

un approccio funzionale:

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

Utilizzando generatore:

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

mezzo di indici:

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