查找列表元素之间的差异

psi*_*lia 103 python list

给定一个数字列表,如何找到其元素的每个(i)和(i+1)之间的差异?使用lambda或列表理解更好吗?

例如:
给定一个列表t=[1,3,6,...],它是要找到一个列表v=[2,3,...],因为3-1=2,6-3=3等等.

Sil*_*ost 136

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

  • 如果你需要绝对差异,`[abs(ji)for i,j in zip(t,t [1:])]` (13认同)
  • 实际上,简单地使用list(map(operator.sub,t [1:],t [:-1]))即可。 (2认同)

Chr*_*lis 100

其他答案是正确的,但如果你正在做数字工作,你可能想考虑numpy.使用numpy,答案是:

v = numpy.diff(t)
Run Code Online (Sandbox Code Playgroud)

  • 这会比“zip”版本更有效吗? (4认同)

Ome*_*gan 32

如果您不想使用numpynor zip,则可以使用以下解决方案:

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


Bak*_*riu 11

您可以使用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
Run Code Online (Sandbox Code Playgroud)

或者使用itertools.islice:

from itertools import islice

def differences(seq):
    nexts = islice(seq, 1, None)
    for x, y in zip(seq, nexts):
        yield y - x
Run Code Online (Sandbox Code Playgroud)

您也可以避免使用该itertools模块:

def differences(seq):
    iterable = iter(seq)
    prev = next(iterable)
    for element in iterable:
        yield element - prev
        prev = element
Run Code Online (Sandbox Code Playgroud)

如果您不需要存储所有结果并支持无限可迭代,所有这些解决方案都可以在恒定空间中工作.


以下是解决方案的一些微观基准:

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
Run Code Online (Sandbox Code Playgroud)

以及其他提议的解决方案:

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
Run Code Online (Sandbox Code Playgroud)

注意:

  • zip(L[1:], L)相当于zip(L[1:], L[:-1]),因为zip已经终止在最短的输入,但它避免了整个副本L.
  • 通过索引访问单个元素非常慢,因为每个索引访问都是python中的方法调用
  • numpy.diff慢,因为它必须首先转换list为a ndarray.显然,如果你开始ndarray这将是快:

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


Cha*_*lli 7

我建议使用

v = np.diff(t)
Run Code Online (Sandbox Code Playgroud)

这是简单易读的。

但是如果你想v拥有与t那时相同的长度

v = np.diff([t[0]] + t) # for python 3.x
Run Code Online (Sandbox Code Playgroud)

或者

v = np.diff(t + [t[-1]])
Run Code Online (Sandbox Code Playgroud)

仅供参考:这仅适用于列表。

对于 numpy 数组

v = np.diff(np.append(t[0], t))
Run Code Online (Sandbox Code Playgroud)


Eug*_*ash 6

使用:=Python 3.8+ 中可用的walrus 运算符:

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


Xav*_*hot 6

在即将到来的 中Python 3.10 release schedule,使用新pairwise功能可以滑动元素对,从而映射到滚动对:

from itertools import pairwise

[y-x for (x, y) in pairwise([1, 3, 6, 7])]
# [2, 3, 1]
Run Code Online (Sandbox Code Playgroud)

中间结果是:

pairwise([1, 3, 6, 7])
# [(1, 3), (3, 6), (6, 7)]
Run Code Online (Sandbox Code Playgroud)