web-dev-qa-db-fra.com

Trouver des différences entre les éléments d'une liste

Étant donné une liste de nombres, comment peut-on trouver des différences entre chaque (i) - ème éléments et ses (i+1) - le?

Est-il préférable d'utiliser une expression lambda ou peut-être une compréhension de liste?

Par exemple:

Étant donné une liste t=[1,3,6,...], le but est de trouver une liste v=[2,3,...] car 3-1=2, 6-3=3, etc.

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

Les autres réponses sont correctes, mais si vous effectuez un travail numérique, vous pouvez envisager Numpy. En utilisant numpy, la réponse est:

v = numpy.diff(t)
96
Christian Alis

Si vous ne souhaitez pas utiliser numpy ni Zip, vous pouvez utiliser la solution suivante:

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

Vous pouvez utiliser itertools.tee et Zip pour construire efficacement le résultat:

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

Ou en utilisant itertools.islice à la place:

from itertools import islice

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

Vous pouvez également éviter d'utiliser le module itertools:

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

Toutes ces solutions fonctionnent dans un espace constant si vous n'avez pas besoin de stocker tous les résultats et de prendre en charge des iterables infinis.


Voici quelques micro-références des solutions:

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

Et les autres solutions proposées:

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

Notez que:

  • Zip(L[1:], L) équivaut à Zip(L[1:], L[:-1]) puisque Zip se termine déjà sur l'entrée la plus courte, mais évite toutefois une copie complète de L.
  • L'accès aux éléments individuels par index est très lent, car chaque accès à l'index est un appel de méthode en python.
  • numpy.diff Est lent car il doit d'abord convertir le list en ndarray. Evidemment si vous commencez par un ndarray ce sera beaucoup plus rapide:

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

Je suggère d'utiliser

v = np.diff(t)

c'est simple et facile à lire.

Mais si vous voulez que v ait la même ligne que t alors

v = np.diff([t[0]] + t) # for python 3.x

ou

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

FYI: cela ne fonctionnera que pour les listes.

pour les tableaux numpy

v = np.diff(np.append(t[0], t))
3

Une approche fonctionnelle:

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

En utilisant générateur:

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

Utilisation d'indices:

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

D'accord. Je pense avoir trouvé la bonne solution:

v = [x[1]-x[0] for x in Zip(t[1:],t[:-1])]
3
psihodelia