Bạn có thể sử dụng itertools.tee
và zip
để xây dựng kết quả một cách hiệu quả:
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
Hoặc sử dụng itertools.islice
thay thế:
from itertools import islice
def differences(seq):
nexts = islice(seq, 1, None)
for x, y in zip(seq, nexts):
yield y - x
Bạn cũng có thể tránh sử dụng itertools
mô-đun:
def differences(seq):
iterable = iter(seq)
prev = next(iterable)
for element in iterable:
yield element - prev
prev = element
Tất cả các giải pháp này hoạt động trong không gian không đổi nếu bạn không cần phải lưu trữ tất cả các kết quả và hỗ trợ lặp vô hạn.
Dưới đây là một số điểm chuẩn vi mô của các giải pháp:
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
Và các giải pháp đề xuất khác:
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
Lưu ý rằng:
zip(L[1:], L)
tương đương với zip(L[1:], L[:-1])
từ zip
đã kết thúc trên đầu vào ngắn nhất, tuy nhiên, nó tránh toàn bộ bản sao của L
.
- Việc truy cập các phần tử đơn lẻ theo chỉ mục rất chậm vì mọi truy cập chỉ mục là một cuộc gọi phương thức trong python
numpy.diff
là chậm vì nó phải đầu tiên chuyển đổi list
một ndarray
. Rõ ràng là nếu bạn bắt đầu với một ndarray
nó sẽ nhanh hơn nhiều :
In [22]: arr = np.array(L)
In [23]: %timeit np.diff(arr)
100 loops, best of 3: 3.02 ms per loop
[abs(j-i) for i,j in zip(t, t[1:])]