(ns foo (:require [clojure.test :refer (with-test is are run-tests)])) (with-test (defn flatten-map [m kf vf] (into {} ((fn g [kv n] (if (map? n) (apply concat (keep (fn [[k v]] (g (conj kv k) v)) n)) (if-let [kfkv (kf kv)] (if-let [vfn (vf n)] [[kfkv vfn]])))) [] m))) (are [m kf vf _ r] (= (flatten-map m kf vf) r) {:a {:b {:c "3" :d "4"} :e "5"}} identity identity -> {[:a :b :c] "3" [:a :b :d] "4" [:a :e] "5"} {:a {:b {:c "3" :d "4"} :e "5"}} #(keyword (apply str (interpose ":" (map name %)))) read-string -> {:a:b:c 3 :a:b:d 4 :a:e 5})) (with-test (defn deep-merge [a b] (reduce (fn [a [kv n]] (assoc-in a kv n)) a ((fn g [kv n] (if (map? n) (apply concat (map (fn [[k v]] (g (conj kv k) v)) n)) [[kv n]])) [] b))) (are [a b _ r] (= (deep-merge a b) r) {:a {:b {:c 3 :d 4} :e 5}} {:a {:b {:c 6 :f 7}} :g 8} -> {:a {:b {:c 6 :d 4 :f 7} :e 5} :g 8})) (with-test (defn mapf [m f & args] (reduce (fn [a [kv n]] (assoc-in a kv n)) {} ((fn g [kv n] (if (map? n) (apply concat (keep (fn [[k v]] (g (conj kv k) v)) n)) (if-let [fna (apply f n args)] [[kv fna]]))) [] m))) (is (= (mapf {:a {:b 3 :c 4} :d 5} #(* % %)) {:a {:b 9 :c 16} :d 25})) (is (= (mapf {:a {:b 3 :c 4} :d 5} #(+ (* %1 %1) %2) 1) {:a {:b 10 :c 17} :d 26})) (is (= (mapf {:a {:b 3 :c 4} :d 0} #(try (/ %2 %1) (catch Exception e)) 1) {:a {:b 1/3 :c 1/4}})))