Skip to content

Instantly share code, notes, and snippets.

@ichramm
Created February 6, 2021 03:28
Show Gist options
  • Save ichramm/86cd13c8b062256e2aaeed0d4c58e94a to your computer and use it in GitHub Desktop.
Save ichramm/86cd13c8b062256e2aaeed0d4c58e94a to your computer and use it in GitHub Desktop.
Compute common factor of multiple maps in Clojure
;; manually
(defn compute-common-factor
[maps]
(if (empty? (rest maps))
;; only one
(first maps)
(let [head (first maps)
maps (rest maps)]
(letfn [(reducer [path obj]
(reduce-kv (fn [m k v]
(let [[v set?] (if (map? v)
;; walk recursively
(let [v (reducer (conj path k) v)]
[v (not-empty v)])
;; return v only if it is the same in all other maps
(when (->> maps
(map #(get-in % (conj path k)))
(remove #(contains? #{v} %))
empty?)
[v true]))]
(if set?
(assoc m k v)
m)))
{}
obj))]
(reducer [] head)))))
;; using clojure.data/diff
;; Problem: Also works on vectors, therefore {:a [1 2]} vs {:a [1 2 3 4]} returns {:a [1 2]}
(defn compute-common-factor
[maps]
(loop [head (first maps)
remaining (rest maps)]
(if (empty? remaining)
head
(recur (last (clojure.data/diff head (first remaining)))
(rest remaining)))))
;; workaround:
(extend-protocol clojure.data/Diff
java.util.List
(diff-similar [a b]
(when (= a b) [nil nil a] [a b nil])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment