edoardo's notes

A Historian Hysteria

A quick preamble

Here we are. It’s that time of year, the last few days before the end of another complete turn of the calendar. The definition of a calendar may be arbitrary, but the first twenty-five days of December are a certainty for anyone who finds it fun to write in a language that can tell a machine what to do. They are the twenty-five days of Advent of Code.

It’s my fifth year and I have tried a lot of things. Including keeping a daily blog, which I already know is going to get really hard before long. So I want to make it clear (to me) what the nature of these posts will be:

I wish everyone who’s participating a lot of fun. Even if it’s going to be tough, we’re going to learn a ton. Let’s get started 🎄🎅🏻


Part 1

We have a table like

3   4
4   3
2   5
1   3
3   9
3   3

We are asked to compute the difference of pairs of numbers, once the lists are sorted. This is a warm-up problem, as always, but we can use many features peculiar to both languages. Python requires at least an initial step in which to read the two columns as list[int]. That done, it’s a one-liner:

def part1(data: tuple[list[int], list[int]]) -> int:
    return sum(abs(a - b) for a, b in zip(sorted(data[0]), sorted(data[1])))

Unpacking, zip(), and generator expressions are the juice of this solution. All very Pythonic ingredients.

Wolfram is even more compact2:

IntegerList /@ SplitLines@day1 // Transpose // Map@Sort // 
  Apply@Subtract/*Abs // Total

Even here it’s a great showcase of the expressive and powerful syntax of the Wolfram Language: we have three operators3 (@, //, /*), Map (and its short version /@) and Apply, two of the most used built-ins.

Part 2

We need to calculate the sum of the values in the first column multiplied by the number of occurrences of that value in the second column. The Python’s standard library has collections.Counter, a kind of dictionary that counts stuff. Here it’s two lines because we need to define the Counter object first:

def part2(data: tuple[list[int], list[int]]) -> int:
    second_counts = Counter(data[1])
    return sum(num * second_counts[num] for num in data[0])

In Wolfram it’s again one line, split to ease readability:

With[{data = IntegerList /@ SplitLines@day1 // Transpose},
 Total[# Lookup[Counts@Last@data, #, 0] & /@ First@data]
 ]
  1. My full solutions can be found here.

  2. IntegerList and SplitLines are not built-ins, but handy utilities I defined myself. They do precisely what they sound like they should do.

  3. Two of them are one the opposite of the other. @ is the “prefix form” (f@x is equivalent to f[x]). // is the “postfix form”: x // f means again f[x]. They are both essential in many circumstances. The last one, /* is the right-composition operator, but we leave it for another time.

#advent of code #learning #programming