2

I have a one dimensional array or list containing integers e.g. x = [0, 2, 4, 7, 8, 12, 15, 23, 28, 39].

I want to have a function that does the following: Return a list/array storing

x[9]-x[8],  x[8]-x[7],  x[7]-x[6], ......., x[1]-x[0]

In this example I should get a list/array giving [11, 5, 8, 3, 4, 1, 3, 2, 2].

I need this function to run in a while loop where for each loop the size of the list/array x grows by 1.

How do I do this in Python or Numpy?

Unlike this other question, this question seeks the difference between elements from the end of a list/array to it's beginning: this question is mathematically different to the other question.

Community
  • 1
  • 1
Sun Bear
  • 7,594
  • 11
  • 56
  • 102
  • Possible duplicate of [Python - Differences between elements of a list](http://stackoverflow.com/questions/2400840/python-differences-between-elements-of-a-list) – James Tobin Jan 27 '17 at 20:56

5 Answers5

3

using the slice notation with a normal list

>>> x = [0, 2, 4, 7, 8, 12, 15, 23, 28, 39]
>>> [ a-b for a,b in zip(x[::-1],x[-2::-1]) ]
[11, 5, 8, 3, 4, 1, 3, 2, 2]
>>> 

to avoid unnecessary copies, a function that yield pairs can be made to help this

>>> def pairwise(iterable):
        it = iter(iterable)
        a = next(it)
        for b in it:
            yield a,b
            a = b


>>> [ a-b for a,b in pairwise(reversed(x))]
[11, 5, 8, 3, 4, 1, 3, 2, 2]
>>> 
Copperfield
  • 8,131
  • 3
  • 23
  • 29
3
In [1084]: x = [0, 2, 4, 7, 8, 12, 15, 23, 28, 39]

numpy.diff does this sort of difference easily

In [1085]: np.diff(x)
Out[1085]: array([ 2,  2,  3,  1,  4,  3,  8,  5, 11])

order is wrong, but can be easily changed with [::-1] (which works with lists and arrays):

In [1086]: np.diff(x)[::-1]
Out[1086]: array([11,  5,  8,  3,  4,  1,  3,  2,  2])
In [1087]: np.diff(x[::-1])
Out[1087]: array([-11,  -5,  -8,  -3,  -4,  -1,  -3,  -2,  -2])

You mention doing this calculation while adding to a list. Let's try that, building a new list, iteratively, from x:

In [1088]: y=[]; dy=[]
In [1089]: for i in x:
      ...:     if y: # not empty
      ...:         dy.insert(0, i-y[-1])
      ...:     y.append(i)

In [1090]: y
Out[1090]: [0, 2, 4, 7, 8, 12, 15, 23, 28, 39]
In [1091]: dy
Out[1091]: [11, 5, 8, 3, 4, 1, 3, 2, 2]

List append is faster than array concatenation (np.append is just a cover for that). So if you are already doing the loop, it makes sense to stick with lists.

One of several ways of doing the difference with lists:

In [1093]: [i-j for i,j in zip(x[1:],x[:-1])]
Out[1093]: [2, 2, 3, 1, 4, 3, 8, 5, 11]

It's simpler to add the list reversal after, rather than figure out how to rewrite the zip terms.

np.diff(a) is just:

In [1094]: xa=np.array(x)
In [1095]: xa[1:]-xa[:-1]
Out[1095]: array([ 2,  2,  3,  1,  4,  3,  8,  5, 11])
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Thanks for providing a very comprehensive answer. :) I accepted it as the answer to my question as the methods shared are concise, comprehensive and well explained. Thanks for also mentioning the difference between list.append and array concatenation. For completeness, and for folks who aren't familiar with numpy, I add here that the numpy solution is easily converted back to a python list by adding `.tolist()` to the end of the numpy array. – Sun Bear Jan 28 '17 at 14:43
2

You must apply the diff function to the inverted list, and change the sign.

import numpy as np 

x = [0, 2, 4, 7, 8, 12, 15, 23, 28, 39]
y = np.asarray(x)
z = -np.diff(y[::-1])
print(z)

Output:

[11  5  8  3  4  1  3  2  2]
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
1

Using numpy, you could do something like this:

def f(x):
    x = np.array(x)
    y = np.copy(x)
    return y[:-1] - x[1:]

In this function, you convert the list x into a numpy array and then copy that array to y. y[:-1] is the whole array excluding the last element and x[1:] is the whole array excluding the first element. Subtracting these two arrays will give you the desired result.

The reason you need to use numpy here is because numpy arrays can do item-wise subtractions between lists, whereas for normal python lists that kind of subtraction doesn't work.

KAL
  • 50
  • 2
0

You want a sliding window over the reversed list, then taking that difference. Here is one way to get a sliding window, copied below.

from itertools import islice

def window(seq, n=2):
    "Returns a sliding window (of width n) over data from the iterable"
    "   s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...                   "
    it = iter(seq)
    result = tuple(islice(it, n))
    if len(result) == n:
        yield result    
    for elem in it:
        result = result[1:] + (elem,)
        yield result

def sliding_differences(l):
    for a, b in window(reversed(l)):
        yield a-b

x = [0, 2, 4, 7, 8, 12, 15, 23, 28, 39]
print(list(sliding_differences(x)))

Outputs:

[11, 5, 8, 3, 4, 1, 3, 2, 2]
Community
  • 1
  • 1
Patrick Haugh
  • 59,226
  • 13
  • 88
  • 96