From 8754f6d6cb0cbe0520fa45c76d92ede19c8ef56f Mon Sep 17 00:00:00 2001 From: Jez Cope Date: Sat, 2 Dec 2017 09:45:46 +0000 Subject: [PATCH] Post: Advent of Code day 2 --- .../2017/02-corruption-checksum.md | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 posts/adventofcode/2017/02-corruption-checksum.md diff --git a/posts/adventofcode/2017/02-corruption-checksum.md b/posts/adventofcode/2017/02-corruption-checksum.md new file mode 100644 index 0000000..4148e61 --- /dev/null +++ b/posts/adventofcode/2017/02-corruption-checksum.md @@ -0,0 +1,66 @@ +--- +title: "Corruption Checksum — Python — #adventofcode Day 2" +description: "In which I detect corrupt spreadsheets." +slug: day-02 +date: 2017-12-02T09:15:46+00:00 +tags: +- Technology +- Learning +- Advent of Code +- Python +series: aoc2017 +--- + + +!!! commentary + Today I went back to plain Python, and I didn't do formal tests because only one test case was given for each part of the problem. I just got stuck in. + + I did write part 2 out in as nested `for` loops as an intermediate step to working out the generator expression. I think that expanded version may have been more readable. + + Having got that far, I couldn't then work out how to finally eliminate the need for an auxiliary function entirely without either sorting the same elements multiple times or sorting each row as it's read. + +First we read in the input, split it and convert it to numbers. `fileinput.input()` returns an iterator over the lines in all the files passed as command-line arguments, or over standard input if no files are given. + +```python +from fileinput import input +sheet = [[int(x) for x in l.split()] for l in input()] +``` + +Part 1 of the challenge calls for finding the difference between the largest and smallest number in each row, and then summing those differences: + +```python +print(sum(max(x) - min(x) for x in sheet)) +``` + +Part 2 is a bit more involved: for each row we have to find the unique pair of elements that divide into each other without remainder, then sum the result of those divisions. We can make it a little easier by sorting each row; then we can take each number in turn and compare it only with the numbers *after* it (which are guaranteed to be larger). Doing this ensures we only make each comparison once. + +```python +def rowsum_div(row): + row = sorted(row) + return sum(y // x for i, x in enumerate(row) for y in row[i+1:] if y % x == 0) + +print(sum(map(rowsum_div, sheet))) +``` + +We can make this code shorter (if not easier to read) by sorting each row as it's read: + +```python +sheet = [sorted(int(x) for x in l.split()) for l in input()] +``` + +Then we can just use the first and last elements in each row for part 1, as we know those are the smallest and largest respectively in the sorted row: + +```python +print(sum(x[-1] - x[0] for x in sheet)) +``` + +Part 2 then becomes a sum over a single generator expression: + +```python +print(sum(y // x for row in sheet + for i, x in enumerate(row) + for y in row[i+1:] + if y % x == 0)) +``` + +Very satisfying!