Sonar Sweep

Part 1

Simplified problem statement:

  • Given a sequence of integers, count how many times there’s an increase in value between two adjacent numbers.

Basically count the number of times a[i+1] > a[i].

Basic idea is to just iterate over pairs (the adjacent value) and filter or count the ones that satisfy the requirement. I’ll resist the usual temptation of trivializing everything with numpy tricks.

Pairs of values in Python can be given by zip(lst, lst[1:]) because zip() stops at the shortest of the iterators. One could also use tee() or similar to avoid making a list copy.

For the filter I prefer a comprehension like sum(x < y for x,y in pairs) or sum(1 for x,y in pairs if x < y). A more militantly functional way to apply the operator across the pairs could be be starmap(, pairs).

aoc = __import__('aoc-common').aoc()
depths = [int(x) for x in aoc.input_text(1).split()]

increases = lambda lst: sum([x < y for x,y in zip(lst, lst[1:])])

aoc.print_answer(1, 1, increases(depths))

Part 2

  • Given a sequence of integers a[i], consider the transformed sequence b[i] = a[i]+a[i+1]+a[i+2] (sum of every three contiguous elements), and count the increases of this new sequence as in Part 1.

A generalized solution that would be purely O(n) no matter what the length of the sums are, would be something like this:

from collections import deque

def contiguous_sums(k, it):
  history = deque()
  val = 0
  for a in it:
    val += a
    if len(history) > k:
      val -= history.popleft()
    if len(history) == k:
      yield val

sums_of_L3 = contiguous_sums(3, depths)

But since k=3 is fixed, the O(n*k) solution works where we just hardcode it works fine, too:

aoc.print_answer(1, 2, increases([x+y+z for x,y,z in zip(depths, depths[1:], depths[2:])]))