首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Clojure -使用specter转换嵌套数据结构,用多个节点替换一个节点

Clojure -使用specter转换嵌套数据结构,用多个节点替换一个节点
EN

Stack Overflow用户
提问于 2019-03-15 06:36:59
回答 3查看 399关注 0票数 6

我正在使用specter来转换Clojure中的嵌套数据结构,但是我还没有掌握它的诀窍。特别是,我正在尝试创建一个转换,它将在任何深度找到与谓词匹配的项,并将其替换为多个项。

代码语言:javascript
复制
[:top
 [:arbitrary 1 2
  [:nesting
   2
   3
   [:needle] ; <-- the thing to find
   ]]]

-->

[:top
 [:arbitrary 1 2
  [:nesting
   2
   3
   [:n1] [:n2] [:n3]  ; <-- 3 items inserted in the place of 1
   ]]]

我不明白的是如何将替换项拼接到父向量中,即如何用三个项替换一个项,而不是一个包含三个子项的项。

EN

回答 3

Stack Overflow用户

发布于 2019-03-15 07:23:01

我不知道如何使用Specter来做到这一点,但这里有一个使用clojure.zip来做到这一点的函数:

代码语言:javascript
复制
(defn splice-replace [zipper smap]
  (loop [loc zipper]
    (if (z/end? loc)
      (z/root loc)
      (recur
       (z/next
        (if-let [sub (smap (z/node loc))]
          (reduce (comp z/right z/insert-right)
                  (z/replace loc (first sub))
                  (rest sub))
          loc))))))

您可以使用数据结构的拉链和从要替换的值到要拼接到其位置的替换值的序列的映射来调用它:

代码语言:javascript
复制
(def zipper
  (z/vector-zip [:top
                 [:arbitrary 1 2
                  [:nesting 2 3 [:needle]]]]))

(splice-replace zipper {[:needle] [[:n1] [:n2] [:n3]]})
 => [:top [:arbitrary 1 2 [:nesting 2 3 [:n1] [:n2] [:n3]]]]

(splice-replace zipper {[:nesting 2 3 [:needle]] (range 3 10)})
=> [:top [:arbitrary 1 2 3 4 5 6 7 8 9]]
票数 3
EN

Stack Overflow用户

发布于 2019-03-15 16:00:48

代码语言:javascript
复制
(defn replace-needle [input replacement]
    (let [needle-parent?     #(= % [:needle])
          NEEDLE-PARENT      (recursive-path
                                 [] p (cond-path
                                          #(and (vector? %) (some needle-parent? %)) [(continue-then-stay [ALL p])]
                                          vector? [ALL p]))
          inject-replacement (fn inject [x] (vec (mapcat #(if (needle-parent? %) replacement [%]) x)))]
        (transform [NEEDLE-PARENT] inject-replacement input)))


(let [input       [:top
                   [:arbitrary 1 2
                    [:nesting 2 3 [:needle]]]]
      replacement [[:n1] [:n2] [:n3]]]
    (replace-needle input replacement))
票数 3
EN

Stack Overflow用户

发布于 2019-03-15 20:41:26

我认为应该可以找到一个包含[:needle]的向量,然后是[:needle]的索引,然后使用srange将新元素拼接到该索引处的父元素中,但我没有找到使用Specter实现这一点的方法。

下面是使用clojure.walk表达相同概念

代码语言:javascript
复制
(require '[clojure.walk :refer [postwalk]])

(postwalk (fn [node]
            (if (and (vector? node)
                     (some (partial = [:needle]) node))
              (let [idx (.indexOf node [:needle])]
                (vec (concat (take idx node)
                             [[:n1] [:n2] [:n3]]
                             (drop (inc idx) node))))
              node))
          data)

;; => [:top [:arbitrary 1 2 [:nesting 2 3 [:n1] [:n2] [:n3]]]]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55173047

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档