# Map Merging in Clojure

## How to combine various kinds of data into maps.

#### October 19, 2021

Advent of Code 2018 Day 4 presents a few interesting challenges.

First of all, this is the first puzzle (of 2018) with input whose records/lines aren't fully self-contained. For instance, the following three lines all pertained to a single 'shift' by Guard #419:

``````[1518-02-09 23:59] Guard #419 begins shift
[1518-02-10 00:16] falls asleep
[1518-02-10 00:47] wakes up
``````

The following seven lines all pertain to a shift for Guard #61:

``````[1518-02-12 00:00] Guard #61 begins shift
[1518-02-12 00:32] falls asleep
[1518-02-12 00:39] wakes up
[1518-02-12 00:52] falls asleep
[1518-02-12 00:53] wakes up
[1518-02-12 00:57] falls asleep
[1518-02-12 00:58] wakes up
``````

I won't bore you with the `loop/recur` required to parse those records here (source). But the goal of parsing these records was a data structure showing when each guard was asleep. When parsed, the sample data provided with the puzzle description looks like this:

``````[{10 (range 5, 25)}
{10 (range 30 55)}
{99 (range 40 50)}
{10 (range 24 29)}
{99 (range 36 46)}
{99 (range 45 55)}]
``````

Each map has a single key (guard-id) and a sequence of minutes when the corresponding guard was asleep. The next task is to merge that data structure into a single map, with all minutes spent sleeping keyed by guard-id:

``````{10 (concat (range 5, 25)
(range 30 55)
(range 24 29))
99 (concat (range 40 50)
(range 36 46)
(range 45 55))}
``````

As is typical of solving problems in Clojure, there's a function for doing just that:

``````(defn merge-naps [parsed]
(apply (partial merge-with concat) parsed))
``````

In a previous post I described my usage of `merge-with` to achieve what the `frequencies` functional already does. Now I'm using `merge-with` in conjunction with `concat` to build the map needed for this solution. Having a merged map for each guard allows for analysis of their sleep patterns (source) into a more helpful data structure:

``````; Guard 10
{:checksum                 (* 10 24)
:total-minutes-slept      50
:naps-on-sleepiest-minute 2}

; Guard 99
{:checksum                 (* 99 45)
:total-minutes-slept      30
:naps-on-sleepiest-minute 3}
``````

From there, we're just a sort-function away, a phrase which here refers to the fact that map keys are also map functions:

``````(defn sleepiest-guard [sort-fn input]
(->> (parse-naps input)
merge-naps
(map analyze-sleep)
(sort-by sort-fn)
last))

(defn part1 [input]
(:checksum (sleepiest-guard :total-minutes-slept input)))

(defn part2 [input]
(:checksum (sleepiest-guard :naps-on-sleepiest-minute input)))
``````

-Michael Whatcott