14

I have a list of integers, i.e.:

values = [55, 55, 56, 57, 57, 57, 57, 62, 63, 64, 79, 80]

I am trying to find the largest difference between two consecutive numbers.

In this case it would be 15 from 64->79.

The numbers can be negative or positive, increasing or decreasing or both. The important thing is I need to find the largest delta between two consecutive numbers.

What is the fastest way to do this? These lists can contain anywhere from hundreds to thousands of integers.

This is the code I have right now:

prev_value = values[0]
largest_delta = 0

for value in values:
  delta = value - prev_value
  if delta > largest_delta:
    largest_delta = delta
  prev_value = value

  return largest_delta

Is there a faster way to do this? It takes a while.

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
Lucas Reno
  • 143
  • 1
  • 4
  • 1
    Your code fails if the deltas are all negative; it returns zero. – John Machin Aug 07 '10 at 01:36
  • Don't forget that if it's a truly massive list you can also 'go wide' - that is, have multiple threads work across different chunks so you use all the cores on the machine. – Eddie Parker Dec 08 '20 at 18:37

5 Answers5

24
max(abs(x - y) for (x, y) in zip(values[1:], values[:-1]))
dan04
  • 87,747
  • 23
  • 163
  • 198
  • 2
    for such large lists though, use `itertools.izip` to avoid constructing a list of tuples in memory – aaronasterling Aug 07 '10 at 01:27
  • That's really quite beautiful :-) – Dirk Groeneveld Aug 07 '10 at 01:27
  • 1
    I _still_ can't get used to this "new" Ptyhon. What happened to my beautiful, readable language? :-) – paxdiablo Aug 07 '10 at 01:29
  • @paxdiablo: I don't understand "new"... zip, map and list comprehension have been in Python since for ever... – Rui Vieira Aug 07 '10 at 01:31
  • @dan04: OP idn't ask for abs(delta) and his sample code doesn't do abs(delta). – John Machin Aug 07 '10 at 01:37
  • 1
    @John - But how could a negative delta be the largest? If `x - y = -15`, then `y - x = 15`. The positive value is always larger (higher), therefore `abs(delta)` is appropriate. – Greg Aug 07 '10 at 01:44
  • 2
    @aaronasterling: In Python 3.x, `zip` doesn't construct a list. I had originally suggested using `itertools.izip` in 2.x, but it wouldn't really help because the slicing builds two new lists. You could use `itertools.islice` to solve that. – dan04 Aug 07 '10 at 01:46
  • @Rui, some of us used Python 1.5. I don't remember that `for` syntax being around forever. Maybe 'forever' has a different meaning for 45-year-old geezers like me :-) – paxdiablo Aug 07 '10 at 01:53
  • 2
    @dan04. good points. You could also avoid building one of the new lists by not slicing the second list. `zip(values[1:], values)`. zip will terminate when `values[1:]` terminates – aaronasterling Aug 07 '10 at 02:06
  • @paxdiablo: Probably "for ever" was too strong :) But at least for 10 years. They were introduced in 2.0, released in 2000. – Rui Vieira Aug 07 '10 at 02:12
  • @Greg: the OP defines delta as value - previous_value. No mention of abs. – John Machin Aug 07 '10 at 02:27
2

With reduce (ugly i guess)

>>> foo = [5, 5, 5, 5, 8, 8, 9]    
>>> print reduce(lambda x, y: (max(x[0], y - x[1]), y), foo, (0, foo[0]))[0]
3
hugo24
  • 1,089
  • 13
  • 21
2

Try timing some of these with the timeit module:

>>> values = [55, 55, 56, 57, 57, 57, 57, 62, 63, 64, 79, 80]
>>> max(values[i+1] - values[i] for i in xrange(0, len(values) - 1))
15
>>> max(v1 - v0 for v0, v1 in zip(values[:-1], values[1:]))
15
>>> from itertools import izip, islice
>>> max(v1 - v0 for v0, v1 in izip(values[:-1], values[1:]))
15
>>> max(v1 - v0 for v0, v1 in izip(values, islice(values,1,None)))
15
>>>
John Machin
  • 81,303
  • 11
  • 141
  • 189
2

This is more as an advertisement for the brilliant recipes in the Python itertools help.

In this case use pairwise as shown in the help linked above.

from itertools import tee, izip

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

values = [55, 55, 56, 57, 57, 57, 57, 62, 63, 64, 79, 80]

print max(b - a for a,b in pairwise(values))
Muhammad Alkarouri
  • 23,884
  • 19
  • 66
  • 101
1

Starting in Python 3.10, the new pairwise function provides a way to slide through pairs of consecutive elements, and thus find each of their differences:

from itertools import pairwise

# values = [55, 55, 56, 57, 57, 57, 57, 62, 63, 64, 79, 80]
max(abs(x-y) for x, y in pairwise(values))
# 15

The intermediate result of pairwise:

pairwise([55, 55, 56, 57, 57, 57, 57, 62, 63, 64, 79, 80])
# [(55, 55), (55, 56), (56, 57), (57, 57), (57, 57), (57, 57), ...]
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190