How to solve Day 6 Advent of Code challenge in Swift

We explore sets, union and intersection, and testing

Pavan Kataria
5 min readDec 6, 2020
An image that reads Day 6: Customs Customs Advent of Code in Swift

The Advent of Code is an Advent calendar consisting of 50 small programming puzzles released every year on December divided over 25 days through to Christmas.

Day 6: Customs Customs challenge

We’re now on Day 6! Well done if you’ve made it this far. In this article we explore how to solve the Customs Customs challenge.

Step 1/4: Understand the premise

You’re told you’re on an aeroplane approaching your destination and passengers are answering a customs declaration form with yes or no questions. You need to tally whoever answered yes to the questions.

Note: Since you have to tally whoever answered you’ll want to start thinking about higher order functions such as filtering and/or reducing as this will make processing this task easier.

You’re given an input which contains an array of answers separated by people in groups. You are told a passenger’s answers are on one line, and groups are separated by a blank line. Like so:

abca
b
c
aba
b
c
ab
aa

Note: Whenever you’re told how input is presented you’ll want to pay careful attention to comments like, one line and blank lines where you’ll need to start thinking about character sets for parsing.

Step 2/4: Parsing the input

I’m using Xcode’s Playgrounds to solve these challenges. First you’ll want to drag your input file into the resources folder like so

Then we’ll need a handy helper method to grab the contents of the input file ready for consumption and store it in the parent page, named AOC2020 in this example, inside its respective Source file so it’s accessible to all the other playground sub-pages.

Then in our Day 6 playground sub-page we can use the method and process the array of strings to morph the document into the input we desire for our algorithmic solutions.

In todays challenge you’ll want to separate out the input by the groups of passengers which are on a blank line represented by the following "\n\n" characters and then each group should be further split into passengers that are split into single lines represented by the following new line "\n" .

Parsing a multi dimensional array input file

And that’s it. Now we’re ready to write the actual solution and passing in input to the method parameter.

Step 3/4: Solving Part 1 understanding `Set` and `Reduce`

A Set stores distinct values of the same type in a collection with no defined ordering. You can use a Set instead of an Array when the order of items are not important, and more importantly when you need to ensure that an item only appears once.

There are methods available to the Set structure that allows us to quickly merge sets together and because of the nature of sets we’ll automatically have a unique output discarding any multiple elements.

a) The boring long way: using for loops and manually counting

Using sets in our example we can write the following to solve Part 1 of the challenge:

Notice how the above code solution uses for loops to traverse through the array and all we’re doing is counting the unique elements of each group’s answers. There is a quicker way, using higher order functions.

b) The elegant quick way — using the reduce function

The reduce function is defined like so:

@inlinable public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

The reduce function is an accumulator that will make traversing a sequence for the purposes of counting extremely lean. You call the reduce method on a sequence such as an array and set the initialResult. The closure gives you the accumulating total defined as nextPartialResult and the next element to operate, on in this case: to add. Baring in mind we are counting two variables in the previous example:
1. countOfAnswers which we’re counting from the groups in the input array
2. counting the uniqueAnswersInGroup a set of unique characters (our answers) derived from each group array.
So we’ll need two reduce functions to achieve the same function. This is what the condensed solution looks like:

Et voila! That’s it!

Step 4/4: Solving Part 2 using `intersection` to find out everyone that’s answered

The problem now extends to tallying only answers that everyone in a group has answered the same of.

Note: whenever you come across a problem where you need to find common values, one solution is to use the Set’s intersection method which returns a set containing only the common elements from two sets.

Here’s what the solution looks like for Part 2 using reduce and the set’s intersection

Because intersection looks for common elements, you can’t start off with an empty initial result. So you’ll need to pass in the first element of the arrays. In this case we’re using the first element of the person’s array in the group.

That’s it for the challenges of Day 6.

To stay tuned for Day 7 challenges follow me here on Medium.

If you enjoyed reading this post please consider liking and sharing so others can find it as well. This would be a great help to me.

You can check me out on Github and Twitter too.

Bonus Step 5/4: Tests

We can ensure we write correct self validating code by writing tests. You simply write the expectations based on the requirements and write down an imaginary API passing in the relevant inputs and then start writing code to help make those tests past — a Test Driven Approach (TDD). Here’s what the tests may look like:

Thank you for reading, I hope you gained some insight and I look forward to seeing you for Day 7 of Advent of Code.

--

--

Pavan Kataria

Engineer Pavan, First of His name, the Unburnt, Lord of the iOS Realm, Bug Breaker, Space Indenter, and New writer — otherwise known as PK