【问题标题】:Deep data structure match & replace first深度数据结构先匹配替换
【发布时间】:2015-08-20 22:51:45
【问题描述】:

我正在尝试找出一种惯用的、高效的和/或功能强大的方法来执行以下操作:

我有一系列如下所示的地图:

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

可以假定:id 字段在任何:_id 中都是唯一的。

另外,我还有两套:

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

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

我需要返回一个与原始序列相同的新序列,但使用来自 substitutes 的值替换 :related 集合中来自 ids 的匹配 id 的 first 出现的所有项目。所以最终的集合应该是这样的:

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

我确信我最终可以编写一些涉及嵌套映射和条件的代码(以迭代的方式思考循环的循环),但在我看来,考虑到我可能拥有的工具,我的思考功能或聪明程度不够可用,在 clojure.core 或 matchwalk 之类的扩展中(如果这些库甚至是要查看的正确库)。

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

替换一个且仅一个出现的:related 值,其:id 匹配来自ids 的值与来自substitutes 的对应值,其中一个出现是第一个(或第n 个)或 rand-nth...) 发生。

【问题讨论】:

  • 您的示例数据无法解析为地图或序列,您的意思是这样吗:({:_id "abc" :related ({:id "123"} {:id "234"})} {:_id "bcd" :related ({:id "345"} {:id "456"})} {:_id "bcd" :related ({:id "234"} {:id "345"})})
  • 是的,错字,谢谢。固定。

标签: clojure functional-programming


【解决方案1】:
(def id-mapping (zipmap ids 
                        (map :id substitutes)))
;; id-mapping -> {"345" "222", "234" "111"}

(clojure.walk/prewalk-replace id-mapping original)

【讨论】:

  • 不确定“id-mapping”是否与您提到的映射完全相同。我认为您的意思是将“345”替换为“222”,将“234”替换为“111”。
【解决方案2】:

假设集合被称为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)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-21
    • 2016-09-13
    • 1970-01-01
    • 1970-01-01
    • 2019-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多