查找列表元素之间的差异

时间:2010-03-08 11:16:11

标签: python list

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

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

11 个答案:

答案 0 :(得分:123)

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

答案 1 :(得分:92)

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

v = numpy.diff(t)

答案 2 :(得分:31)

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

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

答案 3 :(得分:10)

您可以使用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的完整副本。
  • 按索引访问单个元素非常慢,因为每个索引访问都是python中的方法调用
  • numpy.diff ,因为它必须先将list转换为ndarray。显然,如果您使用ndarray 启动,那么 会更快

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

答案 4 :(得分:3)

确定。我想我找到了合适的解决方案:

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

答案 5 :(得分:3)

功能性方法:

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

答案 6 :(得分:0)

我建议使用

v = np.diff(t)

这是简单易读的。

但是,如果您希望vt具有相同的行,则

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

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

具有周期性边界的解决方案

有时需要进行数值积分,以使具有周期性边界条件的列表有所不同(因此第一个元素计算出与最后一个边界的差异。在这种情况下,numpy.roll函数会有所帮助:

v-np.roll(v,1)

前置零的解决方案

另一种numpy解决方案(仅出于完整性考虑)是使用

numpy.ediff1d(v)

这作为numpy.diff起作用,但仅在向量上起作用(它使输入数组变平)。它提供了在结果矢量前添加或添加数字的功能。当处理积累的字段(气象变量(例如,雨水,潜热等)经常发生通量变化)时,这很有用,因为您想要的结果列表与输入变量的长度相同,而第一个条目保持不变。

那你就写

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

当然,您也可以使用np.diff命令来执行此操作,尽管在这种情况下,您需要使用prepend关键字在序列前添加零:

np.diff(v,prepend=0.0) 

以上所有解决方案都返回一个与输入长度相同的向量。

答案 9 :(得分:0)

在即将到来的Python 3.10 release schedule 中,借助新的pairwise功能,可以在元素对之间滑动并映射滚动对:

from itertools import pairwise

[y-x for (x, y) in pairwise([1, 3, 6, 7])]
# [2, 3, 1]

中间结果是:

pairwise([1, 3, 6, 7])
# [(1, 3), (3, 6), (6, 7)]

答案 10 :(得分:-1)

我的方式

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