all / 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17 / 18 / 19 / 20 / 21 / 22 / 23 / 24 / 25
Another day that is fairly straightforward in Haskell, I feel! But in other languages that support functional approaches, it should be straightforward as well.
The answer involves lists of groups of responses:
import Data.List.NonEmpty
import Data.Set
import qualified Data.List.NonEmpty as NE
import qualified Data.Set as S
type Response = Set Char
type Group = NonEmpty Response
parseAnswers :: Set Char -> [Group]
parseAnswers = mapMaybe ((fmap . fmap) S.fromList . NE.nonEmpty . lines)
. splitOn "\n\n"
And now we just need to decide how to aggregate each group. For part 1, this
requires a set union between every Response
in a Group
:
part1 :: [Group] -> Int
part1 = sum . map (S.size . foldr1 S.union)
(foldr1
here is safe because we have a non-empty container)
And for part 2, this requires a set intersection between every Response
in a
Group
:
part2 :: [Group] -> Int
part2 = sum . map (S.size . foldr1 S.intersection)
That's it!
Back to all reflections for 2020
>> Day 06a
benchmarking...
time 124.2 μs (122.7 μs .. 127.3 μs)
0.990 R² (0.970 R² .. 1.000 R²)
mean 125.7 μs (123.1 μs .. 130.8 μs)
std dev 13.18 μs (4.807 μs .. 23.01 μs)
variance introduced by outliers: 82% (severely inflated)
* parsing and formatting times excluded
>> Day 06b
benchmarking...
time 124.8 μs (123.9 μs .. 126.4 μs)
0.997 R² (0.991 R² .. 1.000 R²)
mean 125.4 μs (124.1 μs .. 127.8 μs)
std dev 6.333 μs (790.0 ns .. 11.65 μs)
variance introduced by outliers: 51% (severely inflated)
* parsing and formatting times excluded