深度数据结构匹配并优先替换



我正在尝试找出一种习惯的、高效的和/或功能强大的方法来做以下事情:

我有一个像这样的映射序列:

({:_id "abc" :related ({:id "123"} {:id "234"})}
 {:_id "bcd" :related ({:id "345"} {:id "456"})}
 {:_id "cde" :related ({:id "234"} {:id "345"})})

可以假设:id域在任意一个:_id中是唯一的。

另外,我有两组:

  • ids like ("234" "345")
  • substitutes like ({:id "111"} {:id "222"})

注意,在这个例子中,substitute只包含:id并不意味着它可以被简化为一个id集合。这是一个问题的简化版本,实际数据在映射中有其他键/值对,这些键/值对必须出现。

我需要返回一个与原始序列相同的新序列,但substitutes的值取代了ids在所有项目的:related集合中匹配id的第一个出现。那么最终的集合应该是这样的:

({:_id "abc" :related ({:id "123"} {:id "111"})}
 {:_id "bcd" :related ({:id "222"} {:id "456"})}
 {:_id "cde" :related ({:id "234"} {:id "345"})})

我确信我最终可以编写一些包含嵌套映射和条件的代码(以迭代的方式思考循环的循环),但对我来说,考虑到我可能拥有的工具,无论是在clojure中,我都没有考虑到功能或足够聪明。核心或扩展,如matchwalk(如果它们甚至是正确的库来看)。

另外,如果不要求将其限制为特定策略(即只替换第一个匹配,而忽略其他匹配),感觉会容易得多,但这是一个要求。理想情况下,解决方案应该适用于不同的策略(例如,单一但随机定位的匹配)。策略的一个不变之处是每个id/sub对应该只使用一次。所以:

:related:idids匹配的值替换为substitutes中的对应值,且该值为第一次(或第n次或第n次…)出现

(def id-mapping (zipmap ids 
                        (map :id substitutes)))
;; id-mapping -> {"345" "222", "234" "111"}
(clojure.walk/prewalk-replace id-mapping original)

假设集合名为results:

(require '[clojure.zip :as z])
(defn modify-related
  [results id sub]
  (loop [loc (z/down (z/seq-zip results))
         done? false]
    (if (= done? true)
      (z/root loc)
      (let [change? (->> loc z/node :_id (= id))]
        (recur (z/next (cond change?
                             (z/edit loc (fn [_] identity sub))
                             :else loc))
               change?)))))
(defn modify-results
  [results id sub]
  (loop [loc   (z/down (z/seq-zip results))
         done? false]
    (if (= done? true)
      (z/root loc)
      (let [related (->> loc z/node :related)
            change? (->> related (map :_id) set (#(contains? % id)))]
        (recur (z/next (cond change?
                             (z/edit loc #(assoc % :related (modify-related related id sub)))
                             :else loc))
               change?)))))
(defn sub-for-first
  [results ids substitutes]
  (let [subs (zipmap ids substitutes)]
    (reduce-kv modify-results results subs)))

最新更新