Clojure 函数有效地检查嵌套hashmap中值的更改

Clojure 函数有效地检查嵌套hashmap中值的更改,clojure,Clojure,其动机是检查深嵌套映射中发生了什么变化,有点像中更新的反向 这是一个简单的例子: (def p1{:a{:a1:1:a2:2} :b{:b1:1:b2:2}}) (def p2(在p1[:a:a1]中更新)(持续:更新)) ;;=>{:a{:a1:updated:a2:2} ;;:b{:b1:1:b2:2} (发生了什么变化?p1 p2) ;;=>{:keys[:a:a1]:值:已更新) (发生了什么变化?p2 p1) ;;=>{:keys[:a:a1]:值:2) 我希望,因为clojure映

其动机是检查深嵌套映射中发生了什么变化,有点像中更新的反向

这是一个简单的例子:

(def p1{:a{:a1:1:a2:2}
:b{:b1:1:b2:2}})
(def p2(在p1[:a:a1]中更新)(持续:更新))
;;=>{:a{:a1:updated:a2:2}
;;:b{:b1:1:b2:2}
(发生了什么变化?p1 p2)
;;=>{:keys[:a:a1]:值:已更新)
(发生了什么变化?p2 p1)
;;=>{:keys[:a:a1]:值:2)

我希望,因为clojure映射是持久的数据结构,所以可能有一种智能算法可以通过查看底层结构来解决这个问题,而不是遍历嵌套映射并比较差异。

我可以想象一种像
(if(=map1 map2))这样的直接递归算法:没有变化(递归检查子节点…)
已经很好地利用了结构共享,除非您处理的是非常宽的树(每个节点有很多分支)。在任何情况下,您都可能希望检查哪个解决了问题的一般、非递归版本,并且还可以从直接执行
(=a b)开始

持久数据结构只是关于实现,而不是“查看底层结构”。 正如Joost所说(+1)您可以使用“diff”。它只需要使用“{:keys…:value…}”模式转换答案:

测试:

顺便说一句,在您的情况下,您可以通过“assoc in”而不是“update in”来修改hashmap:

(def p1 {:a {:a1 :1 :a2 :2}
         :b {:b1 :1 :b2 {:b11 :11 :b22 :22}}})

(def p2 {:a {:a1 :updated1 :a2 :2}
         :b {:b1 :1 :b2 {:b11 :updated2 :b22 :updated3}}})

(defn what-changed?* [m]
  (if (not (map? m))
    [(list m)]
    (apply concat (map (fn [k]
                         (map (fn [nest-k]
                                (conj nest-k k))
                              (nested-keys (m k))))
                       (keys m)))))

(defn what-changed? [m1 m2]
  (map (fn [l] {:keys (drop-last l) :value (last l)})
       (nested-keys (second (data/diff m1 m2)))))
(what-changed? p1 p2)
-> ({:keys (:a :a1), :value :updated1}
    {:keys (:b :b2 :b11), :value :updated2}
    {:keys (:b :b2 :b22), :value :updated3})

(what-changed? p2 p1)
-> ({:keys (:a :a1), :value :1}
    {:keys (:b :b2 :b11), :value :11}
    {:keys (:b :b2 :b22), :value :22})
(assoc-in {:a {:a1 :1 :a2 :2}
           :b {:b1 :1 :b2 :2}}
          [:a :a1] :updated)
-> {:a {:a2 :2, :a1 :updated}
    :b {:b2 :2, :b1 :1}}