Clojure Submaps

The gentleman behind Clojure Diary was kind enough to recently post a video based on a small comment I made on his YouTube channel: Clojure Diary - Elegant way of filtering maps based on key value pairs.

(Please check out his channel as he’s doing a great job regularly posting videos about his journey through Clojure!)

In my comment I used a little submap? function from my personal utilities library that I’ve gotten a lot of mileage out of the last year or two.

I thought I’d mention it here. It’s isn’t anything magical, but I think it’s part of my personal standard library from here on out:

(defn submap?
  "Are all of the key-value pairs in `m1` also in `m2`?"
  [m1 m2]
  (= m1 (select-keys m2 (keys m1))))
  
(submap {:a 1, :b 2} {:a 1, :b 2, :c 3}} ; => true
(submap {:a 1, :b 2} {:a 1, :b 4, :c 3}} ; => false

One of the things I use it for constantly is unit tests where I want to assert that a map contains multiple key-value pairs, but I don’t want to assume that a map contains only the specified key-value pairs (in the spirit of the open-world assumption)1.

It also plays nicely with clojure.test, yielding useful test output which shows the full value tested against:

Fail in handler

expected: (utils/submap? {:status 200} (sut/handler {:method :get, :path "/"}))
  actual: (not
           (utils/submap?
            {:status 200}
            {:status 404,
             :body "Not Found",
             :headers {"Content-type" "text/html"}}))

  1. I hear https://github.com/nubank/matcher-combinators is another great option here if you’re ready to invite a new dependency into your project. ↩︎