10
votes
Day 6: Custom Customs
Today's problem description: https://adventofcode.com/2020/day/6
Join the Tildes private leaderboard! You can do that on this page, by entering join code 730956-de85ce0c
.
Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python
with any of the "short names" listed in this page of supported languages):
<details>
<summary>Part 1</summary>
```python
Your code here.
```
</details>
Posting python today because I like how it turned out.
Part 1 & 2
That is...
Very elegant. :D
I hand crafted the sets using dictionaries, and then compared the count of items with the count of members in the group.
Quick and dirty:
Ruby
Part 1
Part 2
Having a built in set class makes this one pretty easy. The set union/intersection operator overloads are handy too.
Went with Python yet again.
Not too happy with solution to part two...Got inspired by the ruby solution by @Crespyl so rewrote the python code to part two to make it a bit cleaner!Part 1
Part 2
What is the cleaner way of handling the new groups? Feels a bit hacky to do the boolean global variable... (edit: see cleaner version below)Part 2 (cleaner version)
Elixir! Took me a while to realize what part two was asking for.
Parts One and Two
FYI, you can use
Enum.sum/1
instead ofEnum.reduce(&(&1 + &2))
!This one wasn't too difficult. It helps if you know some different ways you can store data.
Day 6 Part A – Python
For this I just made a group as I parsed through the entry, then I cast each group over to a set (which doesn't allow duplicates) and back to a list (which does). I typically use that method when I'm looking to find the unique entries within a list.
After that it was just a matter of adding everything together
Day 6 Part B – Python
Part B was a little bit more tricky, I had to rework my data structure a bit to track what each person individually said. Then I iterated through each letter and found ones that every person said yes to. It would probably be easier if I knew how to do an 'intersection' between the different lists.
Tips for Beginners
There are some similarities between this and day 4, at least in terms of how you read in the data. It can be helpful to reuse old code, or improve upon it if you've learned more since then
Your groups will have duplicate entries. You'll need to deal with them in some way. There are multiple options. Some of them mathematical, some of them using programming tricks, and others may take a brute force approach of checking every letter
For part A you only need to look at the group as a whole, but for part B it's necessary to look at each person individually and see how they compare to the rest of the group
Reading up on the difference between data structures can be useful. I use python and so I was able to use the difference between a set and a list to do some of the heavy lifting for part A. They language you're using may let you do something similar
If you want to do things more 'purely mathematically' you'll want to look up the term 'set theory' for the mathematical explanation or 'set operations [YOUR LANGUAGE]' for practical application
Spoiler (do we need to hide these here?)
Not necessarily. It may not be the cleanest, but in my solution I simply check if the occurrences of the letter is equal to the number of people, since one person cannot answer the same question multiple times.
Well, this was nice and easy! Simple and hacky AWK solutions:
Part 1
I just slap the characters to an (associative) array then add its length to the sum.
Part 2
The same, but I add to the array's value and check if it's equal to the number of lines in the group.
haskell again today, nice and concise.
day6.hs
Knowing about some data structures really pays off here - these are just set operations (union and intersection), so converting all the lines to sets and then folding them (in blank-line-separated groups) is really all it needs.Sheets again! While everybody else is all, 'oh! that was a breeze!' -- well, I'm writing some gnarly formulas here.
Part 1
I have Part 2 in my sheet but it's 79 lines long with formatting... so I won't paste it here.
I'm going to keep cracking away at this. There's gotta be a way to cut these formulas down without giving up my arrogant, 'I can do these with one formula' game.
I'm 100% certain there's a more efficient way to do this, but mine works fine apparently. I was surprised at how similar this was to Day 4, at least in the "parse blocked input, and validate" aspect.
Part 1
Part 2
This year I'm using (chicken) scheme. Today's problems lended themselves to a short, elegant solution using sets.
Both parts
Part 1
Part 2 diff
Ryzen 5 2600 vs Raspberry Pi 3b Performance include("Day06/main.jl")
Overall an impressive showing for the Pi, given that it's max power is 12 times less than idle consumption on my desktop!
Ryzen 5 2600 vs Raspberry Pi 3b Performance main() only
Uh, possibly stupid question, but what exactly are those benchmarks measuring? Taking over a second, even on an RPi, makes it seem like Julia is a ridiculously slow language... my relatively inefficient C# code gets both solutions in ~45ms on an ancient overloaded laptop from a cold boot, so something seems off here.
Those benchmarks are measuring my lazy way of executing scripts that I am changing frequently from the REPL, which is to run
include("Day06/main.jl")
, which I think recompiles every time. Fine when I am writing code since I have to do that to run the function at the REPL anyway, definitely slower than one would expect if you were going to run the function many times though. If I do something more reasonable, like include the file and then just runmain()
, the results are much better:Ryzen 5 2600 vs Raspberry Pi 3b Performance main() only
I'll add those results to my original comment and note the difference between the two. The performance impact is indicative of what I understand to be a pretty big issue in Julia development right now, which is often called the "first plot" problem. When you first bring in big packages, notably plotting packages, the whole thing has to be JIT compiled, which can make the first plot super slow, and then the subsequent plots come out quickly. There's some ways around it with caching compiled versions of packages as well as just improving the JIT compiler performance but it can still be pretty poky if you do stupid stuff like I was in those tests!
Rust
Rust
both parts
All of my solutions have been in Elixir, and they all are just a pile of pipes, and I love it. 😁
I used this starter project, so my code expects the input to come in the form of a string argument to each of
part1
andpart2
.Parts 1 and 2
Explanation
Each part is solved by simply calling a
count_yeses
function that counts the total number of "yes" responses, given the following arguments: 1) the input string, and 2) a function1 that builds the appropriate set for each customs declaration.count_yeses
takes the input, and pipes it through the following operations (think of this like an assembly line where each operation takes the result of the previous one):string -> list(string)
set_builder
function to each group:list(string) -> list(set)
list(set)
->list(integer)
list(integer) -> integer
group_to_union_set
collects all the characters in a single group and creates one set out of them. This is the same as creating a set for each line and then union-ing them all together.group_to_intersection_set
puts the characters on each line of a group into a set, then intersects them together to get the overall intersection.1 In order to pass a named function rather than calling it in elixir, you need to use the
&
function capture operator. Functions are also distinguished by their arity (number of arguments taken), so you also need to include that to uniquely identify it:&function_name/arity
.Short in Python
Part 1
Part2
Rust