Day 6: Custom Customs

Puzzle Description

Advent of Code 2020, Day 6

Today is another Ruby day. Again, my original solution is hilariously incompetent, so I just rewrote it.

Solution Summary

  1. Parse input into a List[List[Set[Char]]]
  2. Solve
    • For part 1, sum results of each block, where each block's result is the union of all people in it.
    • For part 2, sum results of each block, where each block's result is the intersection of all people in it.

Part 1

We'll be making use of Set, because this sounds a lot like bitwise operations, but we aren't using a bitmap (because that would require an ugly conversion). Sets let us do these kind of operations on arbitrary "Sets" of objects.

Let's parse our input:

def parse(str: String): List[List[Set[Char]]] =
  str.split("\n\n").map: block =>
    block.linesIterator.map(_.toSet).toList
  .toList

We must pull in set specifically here:

require 'set'

def parse(input)
  input.strip.split("\n\n").map { |block|
    block.strip.split("\n").map { |person| 
      person.strip.chars.to_set
    }
  }
end

Then we can solve part1 just by unioning each block and summing:

def part1(input: List[List[Set[Char]]]): Int =
  input.map: block =>
    block.reduce(_ | _).size
  .sum
def part1(input)
  input.map { |block| 
    block.reduce { |l, r| l | r }.size
  }.sum
end

Part 2

Part 2 is just a matter of swapping | for &:

def part2(input: List[List[Set[Char]]]): Int =
  input.map: block =>
    block.reduce(_ & _).size
  .sum
def part2(input)
  input.map { |block|
    block.reduce { |l, r| l & r }.size
  }.sum
end

And that's part 2 done.

Final Code

def parse(str: String): List[List[Set[Char]]] =
  str.split("\n\n").map: block =>
    block.linesIterator.map(_.toSet).toList
  .toList

def part1(input: List[List[Set[Char]]]): Int =
  input.map: block =>
    block.reduce(_ | _).size
  .sum

def part2(input: List[List[Set[Char]]]): Int =
  input.map: block =>
    block.reduce(_ & _).size
  .sum
def parse(input)
  input.strip.split("\n\n").map { |block|
    block.strip.split("\n").map { |person| 
      person.strip.chars.to_set
    }
  }
end

def part1(input)
  input.map { |block| 
    block.reduce { |l, r| l | r }.size
  }.sum
end

def part2(input)
  input.map { |block|
    block.reduce { |l, r| l & r }.size
  }.sum
end

Benchmark

Part 1

Mean

Error

JVM

3.571 ms

+/- 0.036 ms

JS

12.681 ms

+/- 0.021 ms

Native

1.963 ms

+/- 0.001 ms

Part 2

Mean

Error

JVM

3.145 ms

+/- 0.009 ms

JS

10.796 ms

+/- 0.321 ms

Native

2.010 ms

+/- 0.001 ms

Run it in the browser!