data generic data methods

Author: Chris Zheng  (z@caudate.me)
Date: 27 November 2018
Repository: https://github.com/zcaudate/hara
Version: 3.0.2

1    Introduction

hara.data provides generic methods for clojure datastructures

1.1    Installation

Add to project.clj dependencies:

[hara/base "3.0.2"]

All functions are in the hara.data namespace.

 (use (quote hara.data))

2    Map



assoc-in-new ^

only assoc-in if the value in the original map is nil

v 3.0
(defn assoc-in-new
  [m ks v]
  (if (not (nil? (get-in m ks))) m (assoc-in m ks v)))
link
(assoc-in-new {} [:a :b] 2) => {:a {:b 2}} (assoc-in-new {:a {:b 1}} [:a :b] 2) => {:a {:b 1}}

assoc-in-nnil ^

assoc-in a nested key/value pair to a map only on non-nil values

v 3.0
(defn assoc-in-nnil
  [m arr v]
  (if (not (nil? v)) (assoc-in m arr v) m))
link
(assoc-in-nnil {} [:a :b] 1) => {:a {:b 1}} (assoc-in-nnil {} [:a :b] nil) => {}

assoc-new ^

only assoc if the value in the original map is nil

v 3.0
(defn assoc-new
  ([m k v]
   (if (not (nil? (get m k))) m (assoc m k v)))
  ([m k v & more]
   (apply assoc-new (assoc-new m k v) more)))
link
(assoc-new {:a 1} :b 2) => {:a 1 :b 2} (assoc-new {:a 1} :a 2 :b 2) => {:a 1 :b 2}

assoc-nnil ^

assoc key/value pairs to the map only on non-nil values

v 3.0
(defn assoc-nnil
  ([m k v]
   (if (not (nil? v)) (assoc m k v) m))
  ([m k v & more]
   (apply assoc-nnil (assoc-nnil m k v) more)))
link
(assoc-nnil {} :a 1) => {:a 1} (assoc-nnil {} :a 1 :b nil) => {:a 1}

clean-nested ^

returns a associative with nils and empty hash-maps removed.

v 3.0
(defn clean-nested
  ([m]
   (reduce-kv (fn [out k v]
                (cond (nil? v)
                      out

                      (check/hash-map? v)
                      (let [subv (clean-nested v)]
                        (if (empty? subv)
                          out
                          (assoc out k subv)))

                      :else
                      (assoc out k v)))
              {}
              m)))
link
(clean-nested {:a {:b {:c {}}}}) => {} (clean-nested {:a {:b {:c {} :d 1 :e nil}}}) => {:a {:b {:d 1}}}

dissoc-in ^

disassociates keys from a nested map. Setting `keep` to `true` will not remove a empty map after dissoc

v 3.0
(defn dissoc-in
  ([m [k & ks]]
   (if-not ks
     (dissoc m k)
     (let [nm (dissoc-in (m k) ks)]
       (cond (empty? nm) (dissoc m k)
             :else (assoc m k nm)))))

  ([m [k & ks] keep]
   (if-not ks
     (dissoc m k)
     (assoc m k (dissoc-in (m k) ks keep)))))
link
(dissoc-in {:a {:b 10 :c 20}} [:a :b]) => {:a {:c 20}} (dissoc-in {:a {:b 10}} [:a :b]) => {} (dissoc-in {:a {:b 10}} [:a :b] true) => {:a {}}

dissoc-nested ^

returns `m` without all nested keys in `ks`.

v 3.0
(defn dissoc-nested
  [m ks]
  (let [ks (if (set? ks) ks (set ks))]
    (reduce-kv (fn [out k v]
                 (cond (get ks k)
                       out

                       (check/hash-map? v)
                       (assoc out k (dissoc-nested v ks))

                       :else (assoc out k v)))
               {}
               m)))
link
(dissoc-nested {:a {:b 1 :c {:b 1}}} [:b]) => {:a {:c {}}}

filter-keys ^

filters map based upon map keys

v 3.0
(defn filter-keys
  [pred m]
  (reduce (fn [out [k v]]
            (if (pred k)
              (assoc out k v)
              out))
          {}
          m))
link
(filter-keys even? {0 :a 1 :b 2 :c}) => {0 :a, 2 :c}

filter-vals ^

filters map based upon map values

v 3.0
(defn filter-vals
  [pred m]
  (reduce (fn [out [k v]]
            (if (pred v)
              (assoc out k v)
              out))
          {}
          m))
link
(filter-vals even? {:a 1 :b 2 :c 3}) => {:b 2}

into-nnil ^

like into but filters nil values for both key/value pairs and sequences

v 3.0
(defn into-nnil
  [to from]
  (reduce (fn [i e]
            (if (or (and (coll? e) (not (nil? (second e))))
                    (and (not (coll? e)) (not (nil? e))))
              (conj i e)
              i))
          to from))
link
(into-nnil [] [1 nil 2 3]) => [1 2 3] (into-nnil {:a 1} {:b nil :c 2}) => {:a 1 :c 2}

key-paths ^

the set of all paths in a map, governed by a max level of nesting

v 3.0
(defn key-paths
  ([m] (key-paths m -1 []))
  ([m max] (key-paths m max []))
  ([m max arr]
   (reduce-kv (fn [out k v]
                (cond (and (not= max 1)
                           (check/hash-map? v))
                  (vec (concat out (key-paths v (dec max) (conj arr k))))
                  
                  :else (conj out (conj arr k))))
              []
              m)))
link
(key-paths {:a {:b 1} :c {:d 1}}) => (contains [[:c :d] [:a :b]] :in-any-order) (key-paths {:a {:b 1} :c {:d 1}} 1) => (contains [[:c] [:a]] :in-any-order)

keys-nested ^

the set of all nested keys in a map

v 3.0
(defn keys-nested
  ([m] (reduce-kv (fn [s k v]
                    (if (check/hash-map? v)
                      (set/union (conj s k) (keys-nested v))
                      (conj s k)))
                  #{}
                  m)))
link
(keys-nested {:a {:b 1 :c {:d 1}}}) => #{:a :b :c :d}

map-entries ^

manipulates a map given the function

v 3.0
(defn map-entries
  [f m]
  (->> (map f m)
       (into {})))
link
(map-entries (fn [[k v]] [(keyword (str v)) (name k)]) {:a 1 :b 2 :c 3}) => {:1 "a", :2 "b", :3 "c"}

map-keys ^

changes the keys of a map

v 3.0
(defn map-keys
  [f m]
  (reduce (fn [out [k v]]
            (assoc out (f k) v))
          {}
          m))
link
(map-keys inc {0 :a 1 :b 2 :c}) => {1 :a, 2 :b, 3 :c}

map-vals ^

changes the values of a map

v 3.0
(defn map-vals
  [f m]
  (reduce (fn [out [k v]]
            (assoc out k (f v)))
          {}
          m))
link
(map-vals inc {:a 1 :b 2 :c 3}) => {:a 2, :b 3, :c 4}

merge-nested ^

merges nested values from left to right.

v 3.0
(defn merge-nested
  ([] {})
  ([m] m)
  ([m1 m2]
   (reduce-kv (fn [out k v]
                (let [v1 (get out k)]
                  (cond (nil? v1)
                        (assoc out k v)

                        (and (check/hash-map? v) (check/hash-map? v1))
                        (assoc out k (merge-nested v1 v))

                        (= v v1)
                        out

                        :else
                        (assoc out k v))))
              (or m1 {})
              m2))
  ([m1 m2 & ms]
   (apply merge-nested (merge-nested m1 m2) ms)))
link
(merge-nested {:a {:b {:c 3}}} {:a {:b 3}}) => {:a {:b 3}} (merge-nested {:a {:b {:c 1 :d 2}}} {:a {:b {:c 3}}}) => {:a {:b {:c 3 :d 2}}}

merge-new ^

only merge if the value in the original map is nil

v 3.0
(defn merge-new
  ([] nil)
  ([m] m)
  ([m1 m2]
   (reduce (fn [i [k v]]
             (if (not (nil? (get i k)))
               i
               (assoc i k v)))
           m1 m2))
  ([m1 m2 & more]
   (apply merge-new (merge-new m1 m2) more)))
link
(merge-new {:a 1} {:b 2}) => {:a 1 :b 2} (merge-new {:a 1} {:a 2}) => {:a 1}

merge-new-nested ^

merges nested values from left to right, provided the merged value does not exist

v 3.0
(defn merge-new-nested
  ([] nil)
  ([m] m)
  ([m1 m2]
   (reduce-kv (fn [out k v]
                (let [v1 (get out k)]
                  (cond (nil? v1)
                        (assoc out k v)

                        (and (check/hash-map? v) (check/hash-map? v1))
                        (assoc out k (merge-new-nested v1 v))

                        :else
                        out)))
              (or m1 {})
              m2))
  ([m1 m2 & more]
   (apply merge-new-nested (merge-new-nested m1 m2) more)))
link
(merge-new-nested {:a {:b 2}} {:a {:c 2}}) => {:a {:b 2 :c 2}} (merge-new-nested {:b {:c :old}} {:b {:c :new}}) => {:b {:c :old}}

merge-nnil ^

merges key/value pairs into a single map only if the value exists

v 3.0
(defn merge-nnil
  ([] nil)
  ([m]
   (reduce (fn [i [k v]]
             (if (not (nil? v)) (assoc i k v) i))
           {} m))
  ([m1 m2]
   (reduce (fn [i [k v]]
             (if (not (nil? v)) (assoc i k v) i))
           (merge-nnil m1) m2))
  ([m1 m2 & more]
   (apply merge-nnil (merge-nnil m1 m2) more)))
link
(merge-nnil {:a nil :b 1}) => {:b 1} (merge-nnil {:a 1} {:b nil :c 2}) => {:a 1 :c 2} (merge-nnil {:a 1} {:b nil} {:c 2}) => {:a 1 :c 2}

retract-in ^

reversed the changes by transform-in

v 3.0
(defn retract-in
  [m rels]
  (reduce (fn [out [to from]]
            (let [v (get-in m to)]
              (-> out
                  (assoc-in-nnil from v)
                  (dissoc-in to))))
          m
          (reverse rels)))
link
(retract-in {:b 2, :c {:d 1}} {[:c :d] [:a]}) => {:a 1 :b 2}

select-keys-nnil ^

selects only the non-nil key/value pairs from a map

v 3.0
(defn select-keys-nnil
  [m ks]
  (reduce (fn [i k]
            (let [v (get m k)]
              (if (not (nil? v))
                (assoc i k v)
                i)))
          nil ks))
link
(select-keys-nnil {:a 1 :b nil} [:a :b]) => {:a 1} (select-keys-nnil {:a 1 :b nil :c 2} [:a :b :c]) => {:a 1 :c 2}

transform-in ^

moves values around in a map according to a table

v 3.0
(defn transform-in
  [m rels]
  (reduce (fn [out [to from]]
            (let [v (get-in m from)]
              (-> out
                  (assoc-in-nnil to v)
                  (dissoc-in from))))
          m
          rels))
link
(transform-in {:a 1 :b 2} {[:c :d] [:a]}) => {:b 2, :c {:d 1}}

transpose ^

sets the vals and keys and vice-versa

v 3.0
(defn transpose
  [m]
  (reduce (fn [out [k v]]
            (assoc out v k))
          {}
          m))
link
(transpose {:a 1 :b 2 :c 3}) => {1 :a, 2 :b, 3 :c}

unique ^

returns a map of all key/value pairs that differ from a second map

v 3.0
(defn unique
  [m1 m2]
  (reduce (fn [i [k v]]
            (if (not= v (get m2 k))
              (assoc i k v)
              i))
          nil m1))
link
(unique {:a 1} {:a 2}) => {:a 1} (unique {:a 1 :b 2} {:b 2}) => {:a 1} (unique {:b 2} {:b 2 :a 1}) => nil

unique-nested ^

all nested values in `m1` that are unique to those in `m2`.

v 3.0
(defn unique-nested
  [m1 m2]
  (reduce-kv (fn [out k v]
               (let [v2 (get m2 k)]
                 (cond (nil? v2)
                       (assoc out k v)

                       (and (check/hash-map? v) (check/hash-map? v2))
                       (let [subv (unique-nested v v2)]
                         (if (empty? subv)
                           out
                           (assoc out k subv))) (= v v2)
                       out

                       :else
                       (assoc out k v))))
             {}
             m1))
link
(unique-nested {:a {:b 1}} {:a {:b 1 :c 1}}) => {} (unique-nested {:a {:b 1 :c 1}} {:a {:b 1}}) => {:a {:c 1}}

update-in-nnil ^

update-in a nested key/value pair only if the value exists

v 3.0
(defn update-in-nnil
  [m arr f & args]
  (let [v (get-in m arr)]
    (if (not (nil? v))
      (assoc-in m arr (apply f v args))
      m)))
link
(update-in-nnil {:a {:b 1}} [:a :b] inc) => {:a {:b 2}} (update-in-nnil {} [:a :b] inc) => {}

update-keys-in ^

updates all keys in a map with given function

v 3.0
(defn update-keys-in
  [m arr f & args]
  (let [key-fn (fn [m]
                 (map/map-keys (fn [k] (apply f k args)) m))]
    (cond (sequential? arr)
          (if (empty? arr)
            (key-fn m)
            (update-in m arr key-fn))

          (number? arr)
          (if (= 1 arr)
            (key-fn m)
            (reduce (fn [out kpath]
                      (update-in out kpath key-fn))
                    m
                    (key-paths m (dec arr))))

          :else (throw (ex-info "`arr` has to be a seq or a number." {:input arr})))))
link
(update-keys-in {:x {["a" "b"] 1 ["c" "d"] 2}} [:x] string/joinl) => {:x {"ab" 1 "cd" 2}} (update-keys-in {:a {:c 1} :b {:d 2}} 2 name) => {:b {"d" 2}, :a {"c" 1}}

update-vals-in ^

updates all values in a map with given function

v 3.0
(defn update-vals-in
  [m arr f & args]
  (let [val-fn (fn [m]
                 (map/map-vals (fn [v] (apply f v args)) m))]
    (cond (sequential? arr)
          (if (empty? arr)
            (val-fn m)
            (update-in m arr val-fn))

          (number? arr)
          (if (= 1 arr)
            (val-fn m)
            (reduce (fn [out kpath]
                      (update-in out kpath val-fn))
                    m
                    (key-paths m (dec arr))))

          :else (throw (ex-info "`arr` has to be a seq or a number." {:input arr})))))
link
(update-vals-in {:a 1 :b 2} [] inc) => {:a 2 :b 3} (update-vals-in {:a {:c 1} :b 2} [:a] inc) => {:a {:c 2} :b 2} (update-vals-in {:a {:c 1} :b {:d 2}} 2 inc) => {:a {:c 2} :b {:d 3}} (update-vals-in {:a 1 :b 2} 1 inc) => {:a 2, :b 3}

3    Diff



changed ^

outputs what has changed between the two maps

v 3.0
(defn changed
  [new old]
  (->> (diff new old)
       ((juxt :> :+))
       (apply merge)
       (reduce-kv (fn [out ks v]
                    (assoc-in out ks v))
                  {})))
link
(changed {:a {:b {:c 3 :d 4}}} {:a {:b {:c 3}}}) => {:a {:b {:d 4}}}

diff ^

finds the difference between two maps

v 3.0
(defn diff
  ([m1 m2] (diff m1 m2 false))
  ([m1 m2 reversible]
   (let [diff (hash-map :+ (diff-new m1 m2)
                        :- (diff-new m2 m1)
                        :> (diff-changes m1 m2))]
     (if reversible
       (assoc diff :< (diff-changes m2 m1))
       diff))))
link
(diff {:a 2} {:a 1}) => {:+ {} :- {} :> {[:a] 2}} (diff {:a {:b 1 :d 3}} {:a {:c 2 :d 4}} true) => {:+ {[:a :b] 1} :- {[:a :c] 2} :> {[:a :d] 3} :< {[:a :d] 4}}

patch ^

use the diff to convert one map to another in the forward direction based upon changes between the two.

v 3.0
(defn patch
  [m diff]
  (->> m
       (#(reduce-kv (fn [m arr v]
                      (update-in m arr merge-or-replace v))
                    %
                    (merge (:+ diff) (:> diff))))
       (#(reduce (fn [m arr]
                   (map/dissoc-in m arr))
                 %
                 (keys (:- diff))))))
link
(let [m1 {:a {:b 1 :d 3}} m2 {:a {:c 2 :d 4}} df (diff m2 m1)] (patch m1 df)) => {:a {:c 2 :d 4}}

unpatch ^

use the diff to convert one map to another in the reverse direction based upon changes between the two.

v 3.0
(defn unpatch
  [m diff]
  (->> m
       (#(reduce-kv (fn [m arr v]
                      (update-in m arr merge-or-replace v))
                    %
                    (merge (:- diff) (:< diff))))
       (#(reduce (fn [m arr]
                   (map/dissoc-in m arr))
                 %
                 (keys (:+ diff))))))
link
(let [m1 {:a {:b 1 :d 3}} m2 {:a {:c 2 :d 4}} df (diff m2 m1 true)] (unpatch m2 df)) => {:a {:b 1 :d 3}}

4    Seq



element-of ^

finds the element within an array

v 3.0
(defn element-of
  [pred coll]
  (loop [[x & more :as coll] coll]
    (cond (empty? coll) nil

          (pred x) x

          :else
          (recur more))))
link
(element-of keyword? [1 2 :hello 4]) => :hello

flatten-all ^

flattens all elements the collection

v 3.0
(defn flatten-all
  [x]
  (filter (complement coll?)
          (rest (tree-seq coll? seq x))))
link
(flatten-all [1 2 #{3 {4 5}}]) => [1 2 3 4 5]

index-of ^

finds the index of the first matching element in an array

v 3.0
(defn index-of
  [pred coll]
  (loop [[x & more :as coll] coll
         i 0]
    (cond (empty? coll) -1

          (pred x) i

          :else
          (recur more (inc i)))))
link
(index-of even? [1 2 3 4]) => 1 (index-of keyword? [1 2 :hello 4]) => 2

positions ^

find positions of elements matching the predicate

v 3.0
(defn positions
  [pred coll]
  (keep-indexed (fn [idx x]
                  (when (pred x)
                    idx))
                coll))
link
(positions even? [5 5 4 4 3 3 2 2]) => [2 3 6 7]

remove-index ^

removes element at the specified index

v 3.0
(defn remove-index
  [coll i]
  (cond (vector? coll)
        (reduce conj
                (subvec coll 0 i)
                (subvec coll (inc i) (count coll)))

        :else
        (keep-indexed #(if (not= %1 i) %2) coll)))
link
(remove-index [:a :b :c :d] 2) => [:a :b :d]

5    Complex



assocs ^

similar to `assoc` but conditions of association is specified through `sel` (default: `identity`) and well as merging specified through `func` (default: `combine`).

v 3.0
(defn assocs
  ([m k v] (assocs m k v identity combine/combine))
  ([m k v sel func]
   (let [z (get m k)]
     (cond (nil? z) (assoc m k v)
           :else
           (assoc m k (combine/combine z v sel func))))))
link
(assocs {:a #{1}} :a #{2 3 4}) => {:a #{1 2 3 4}} (assocs {:a {:id 1}} :a {:id 1 :val 1} :id merge) => {:a {:val 1, :id 1}} (assocs {:a #{{:id 1 :val 2} {:id 1 :val 3}}} :a {:id 1 :val 4} :id merges) => {:a #{{:id 1 :val #{2 3 4}}}}

combine ^

takes `v1` and `v2`, which can be either values or sets of values and merges them into a new set.

v 3.0
(defn combine
  ([] nil)
  ([m] m)
  ([v1 v2]
   (cond (nil? v2) v1
         (nil? v1) v2

         (set? v1)
         (cond (set? v2)
               (set/union v1 v2)
               :else (conj v1 v2))

         :else
         (cond (set? v2)
               (conj v2 v1)

               (= v1 v2) v1
               :else #{v1 v2})))

  ([v1 v2 sel func]
   (-> (cond (nil? v2) v1
             (nil? v1) v2
             (set? v1)
             (cond (set? v2)
                   (combine-set v1 v2 sel func)

                   :else (combine-value v1 v2 sel func))
             :else
             (cond (set? v2)
                   (combine-value v2 v1 sel func)

                   (hand/eq-> v1 v2 sel)
                   (func v1 v2)

                   (= v1 v2) v1
                   :else #{v1 v2}))
       (combine-internal sel func))))
link
(combine 1 2) => #{1 2} (combine #{1} 1) => #{1} (combine #{{:id 1} {:id 2}} #{{:id 1 :val 1} {:id 2 :val 2}} :id merge) => #{{:id 1 :val 1} {:id 2 :val 2}}

decombine ^

takes set or value `v` and returns a set with elements matching sel removed

v 3.0
(defn decombine
  [v dv]
  (cond (set? v)
        (let [res (cond (set? dv)
                        (set/difference v dv)

                        (ifn? dv)
                        (set (filter (complement dv) v))

                        :else (disj v dv))]
          (if-not (empty? res) res))
        :else
        (if-not (hand/check-> v dv) v)))
link
(decombine 1 1) => nil (decombine 1 2) => 1 (decombine #{1} 1) => nil (decombine #{1 2 3 4} #{1 2}) => #{3 4} (decombine #{1 2 3 4} even?) => #{1 3}

dissocs ^

similar to `dissoc` but allows dissassociation of sets of values from a map.

v 3.0
(defn dissocs
  [m k]
  (cond (vector? k)
        (let [[k v] k
              z (get m k)
              res (combine/decombine z v)]
          (if (nil? res)
            (dissoc m k)
            (assoc m k res)))
        :else
        (dissoc m k)))
link
(dissocs {:a 1} :a) => {} (dissocs {:a #{1 2}} [:a #{0 1}]) => {:a #{2}} (dissocs {:a #{1 2}} [:a #{1 2}]) => {}

dissocs-in ^

similiar to `dissoc-in` but can move through sets.

v 3.0
(defn dissocs-in
  [m [k & ks :as all-ks]]
  (cond (nil? ks) (dissocs m k)

        (vector? k) (dissocs-in-filtered m all-ks)

        :else
        (let [val (get m k)]
          (cond (set? val)
                (assoc m k (set (map #(dissocs-in % ks) val)))
                :else (assoc m k (dissocs-in m ks))))))
link
(dissocs-in {:a #{{:b 1 :c 1} {:b 2 :c 2}}} [:a :b]) => {:a #{{:c 1} {:c 2}}} (dissocs-in {:a #{{:b #{1 2 3} :c 1} {:b #{1 2 3} :c 2}}} [[:a [:c 1]] [:b 1]]) => {:a #{{:b #{2 3} :c 1} {:b #{1 2 3} :c 2}}}

gets ^

returns the associated values either specified by a key or a key and predicate pair.

v 3.0
(defn gets
  [m k]
  (if-not (vector? k)
    (get m k)
    (let [[k prchk] k
          val (get m k)]
      (if-not (set? val) val
              (-> (filter #(hand/check?-> % prchk) val) set)))))
link
(gets {:a 1} :a) => 1 (gets {:a #{0 1}} [:a zero?]) => #{0} (gets {:a #{{:b 1} {}}} [:a :b]) => #{{:b 1}}

gets-in ^

similar in style to `get-in` with operations on sets. returns a set of values.

v 3.0
(defn gets-in
  [m ks]
  (-> (gets-in-loop m ks) set (disj nil)))
link
(gets-in {:a 1} [:a]) => #{1} (gets-in {:a 1} [:b]) => #{} (gets-in {:a #{{:b 1} {:b 2}}} [:a :b]) => #{1 2}

merges ^

like `merge` but works across sets and will also combine duplicate key/value pairs together into sets of values.

v 3.0
(defn merges
  ([m1 m2] (merges m1 m2 identity combine/combine))
  ([m1 m2 sel] (merges m1 m2 sel combine/combine))
  ([m1 m2 sel func]
   (reduce-kv (fn [out k v]
                (assoc out k (combine/combine (get out k) v sel func)))
              m1
              m2)))
link
(merges {:a 1} {:a 2}) => {:a #{1 2}} (merges {:a #{{:id 1 :val 1}}} {:a {:id 1 :val 2}} :id merges) => {:a #{{:id 1 :val #{1 2}}}}

merges-nested ^

like `merges` but works on nested maps

v 3.0
(defn merges-nested
  ([] nil)
  ([m] m)
  ([m1 m2] (merges-nested m1 m2 identity combine/combine))
  ([m1 m2 sel] (merges-nested m1 m2 sel combine/combine))
  ([m1 m2 sel func]
   (reduce-kv (fn [out k v]
                (let [v1 (get out k)]
                  (cond (not (and (check/hash-map? v1) (check/hash-map? v)))
                        (assoc out k (combine/combine v1 v sel func))

                        :else
                        (assoc out k (merges-nested v1 v sel func)))))
              m1
              m2)))
link
(merges-nested {:a {:b 1}} {:a {:b 2}}) => {:a {:b #{1 2}}} (merges-nested {:a #{{:foo #{{:bar #{{:baz 1}}}}}}} {:a #{{:foo #{{:bar #{{:baz 2}}}}}}} hash-map? merges-nested) => {:a #{{:foo #{{:bar #{{:baz 2}}} {:bar #{{:baz 1}}}}}}}