0

I want to subtract consecutive numbers in an array a:

a = [1, 3, 4, 7, 9, 2]

The resulting array should be:

res = [2, 3, 7]

So I want to subtract 1-3, 4-7 and then 9-2 in Python and get the absolute value. How can I make a code or function to do this?

I tried doing

res = a[0:] - a[:+1]

but this gives me

res = [-2, -3, -6, -8, -1]
Kins
  • 547
  • 1
  • 5
  • 22
  • Use `abs` for absolute value if you don't want the negative signs. – Stef Jul 04 '23 at 07:16
  • 1
    What made you think `res= a[0:]-a[:+1]` would do anything remotely close to what you want to do? And no it would not give you `res = [-2, -3, -6, -8, -1]` at all either. Please put some actual effort into it, especially since this looks like your homework. – blhsing Jul 04 '23 at 07:20
  • `res = [x - y for x, y in zip(a[::2], a[1::2])]`. I left out one small part because I don't want to do all the homework for you. – Matthias Jul 04 '23 at 07:23
  • Does this answer your question? [Iterating over every two elements in a list](https://stackoverflow.com/questions/5389507) – Jorge Luis Jul 04 '23 at 07:24

5 Answers5

2

I think this is the most efficient way to subtract consecutive array elements using zip()

a = [1, 3, 4, 7, 9, 2]
res = [abs(y-x) for x,y in zip(a[::2], a[1::2])]
print(res)

Output:

[2, 3, 7]
Dejene T.
  • 973
  • 8
  • 14
1
def subtractions_by_pairs(a):
    res = []
    for i in range(0, len(a), 2):
        x, y = a[i:i+2]
        res.append(abs(y-x))
    return res

print(subtractions_by_pairs([1, 3, 4, 7, 9, 2]))
# [2, 3, 7]

Or using zip to combine two sequences, and using a[::2] and a[1::2] to get the subsequences of element at even indices and odd indices:

def subtractions_by_pairs(a):
    assert(len(a) % 2 == 0)
    return [abs(y - x) for x, y in zip(a[::2], a[1::2])]
Stef
  • 13,242
  • 2
  • 17
  • 28
0

Those are lists, not arrays. You need to iterate over the indices, but you only really need every other index starting with zero.

This is readily implemented using a list comprehension.

[
  abs(a[i] - a[i+1]) 
  for i in range(0, len(a) - 1, 2)
]

Result:

[2, 3, 7]

By subtracting 1 from the length in the call to range, we can prevent an error when a is of uneven length.

>>> a = [1, 3, 4, 7, 9]
>>> [
...   abs(a[i] - a[i+1]) 
...   for i in range(0, len(a) - 1, 2)
... ]
[2, 3]
Chris
  • 26,361
  • 5
  • 21
  • 42
0

Using zip:

a = [1, 3, 4, 7, 9, 2]

# using slicing
res = [abs(a-b) for a,b in zip(a[::2], a[1::2])]

# or with an iterator
i = iter(a)
res = [abs(a-b) for a,b in zip(i, i)]

Output: [2, 3, 7]

If you want to perform more complex operations, you should maybe use , which allows you to perform vectorial operations similarly to what you were trying to do with res= a[0:]-a[:+1]:

import numpy as np

a = np.array([1, 3, 4, 7, 9, 2])

res = abs(a[::2] - a[1::2])

Output: array([2, 3, 7])

mozway
  • 194,879
  • 13
  • 39
  • 75
0

Lemme add some functional kung-fu with the benefit of introducing some useful libraries and concepts:

from operator import sub

[*map(abs, map(sub, i:=iter(a), i))]
# [2, 3, 7]

Some docs:

user2390182
  • 72,016
  • 6
  • 67
  • 89
  • 1
    And in Python 3.12 we´ll be able to do: `[*map(abs, starmap(sub, batched(a, 2)))]` – slothrop Jul 04 '23 at 07:55
  • 1
    Those will be the days =) – user2390182 Jul 04 '23 at 07:56
  • Alternatively: `d = lambda x,y: abs(x-y)); i = iter(a); list(map(d, i, i))`. In general, there is no need to combine `zip` and `starmap`: you can use `map` directly with more than one sequence. – Stef Jul 04 '23 at 09:05
  • @Stef That is indeed a simplification. Fixed it while avoiding the ugly lambda. The double map kinda emphasizes the function chaining. – user2390182 Jul 04 '23 at 11:27