Calculate difference between adjacent items in a python list
I have a list of millions of numbers. I want to find out if the difference between each number in the ordered list is the same for the entire list.
list_example = 开发者_StackOverflow中文版[ 0, 5, 10, 15, 20, 25, 30, 35, 40, ..etc etc etc]
What's the best way to do this?
My try:
import collections
list_example = [ 0, 5, 10, 15, 20, 25, 30, 35, 40 ]
count = collections.Counter()
for x,y in zip(list_example[0::],list_example[1::]):
print x,y,y-x
count[y-x] +=1
if len( count ) == 1:
print 'Differences all the same'
Result:
0 5 5
5 10 5
10 15 5
15 20 5
20 25 5
25 30 5
30 35 5
35 40 5
Differences all the same
Using pure Python:
>>> x = [0,5,10,15,20]
>>> xdiff = [x[n]-x[n-1] for n in range(1,len(x))]
>>> xdiff
[5, 5, 5, 5]
>>> all([xdiff[0] == xdiff[n] for n in range(1,len(xdiff))])
True
It's a little easier, and probably faster, if you use NumPy:
>>> import numpy as np
>>> xdiff = np.diff(x)
>>> np.all(xdiff[0] == xdiff)
True
But both of these create two extra lists (or arrays, in the case of NumPy) which may gobble up your available memory if you have millions of numbers.
The straight approach here is the best:
x = s[1] - s[0]
for i in range(2, len(s)):
if s[i] - s[i-1] != x: break
else:
#do some work here...
Need notice that the list may have millions of numbers. So ideally, we shouldn't iterate over the entire list unless it's necessary. Also we need avoid construct new list, which may have significant memory consumption. Using all and a generator will solve the problem
>>> x = [5, 10, 15, 20, 25]
>>> all(x[i] - x[i-1] == x[i+1] - x[i] for i in xrange(1, len(x) - 1))
True
itertools.izip is great for this kind of thing:
>>> lst = [1,1,2,3,5,8]
>>> [y-x for x, y in itertools.izip (lst, lst[1:])]
[0, 1, 1, 2, 3]
I came to this while playing around:
>>> exm = [0,5,10,15,20,25,30,35]
>>> len(set(exm[a + 1] - exm[a] for a in range(0, len(exm) - 1))) == 1
What I do is for each pair of consecutive items determine their difference in a generator. I then add all those differences to a set to only keep the unique values. If the length of this set is 1 all the differences are the same.
Edit: Looking at cldy's answer you can halt execution early when any item is found not the be the same as your initial difference:
>>> exm = [0,5,10,15,20,25,30,35]
>>> initial_diff = exm[1] - exm[0]
>>> difference_found = any((exm[a + 1] - exm[a]) != initial_diff
for a in range(1, len(exm) - 1))
>>> x=[10,15,20,25]
>>> diff=(x[-1]-x[0])/(len(x)-1)
>>> diff
5
>>> all(x[i]+diff==x[i+1] for i in range(len(x)-1))
True
Here's an example using the diff function in numpy
.
e.g.
import numpy
numpy_array = numpy.zeros(10**6)
for i in xrange(10**6):
numpy_array[i] = i
print numpy.any(numpy.diff(a) == 1)
True
Here's a solution using iterators just for comparison.. and possibly an advantage of not needing to know the length of your input data; you might be able to avoid having the millions of list items loaded into memory in the first place...
from itertools import tee, izip
# From itertools recipes: http://docs.python.org/library/itertools.html
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
class DifferenceError(Exception):
pass
def difference_check(data):
idata = pairwise(data)
(a,b) = idata.next()
delta = b - a
for (a,b) in idata:
if b - a != delta:
raise DifferenceError("%s -> %s != %s" % (a,b,delta))
return True
I had a similar problem and I used the following method:
foo = map(lambda x: lst[x+1]-lst[x],range(len(lst)-1))
精彩评论