Clojure的pre/post-walk函数,带有从根路径开始的路径

5

我知道的

我熟悉clojure.walk/prewalk和clojure.walk/postwalk。

我的需求

我需要类似于clojure.walk/prewalk和clojure.walk/postwalk的东西——但我还需要到达节点所需的路径,而prewalk/postwalk只提供了节点,没有实际路径。

示例

因此,如果我们有一个结构

[ {:cat "Garfield", :dog "DogeCoin"} [:a :b {:site "so"}]]

然后,我希望我的函数被调用并附带参数:

[] [ {:cat "Garfield", :dog "DogeCoin"} [:a :b {:site "so"}]]

[0] {:cat "Garfield", :dog "DogeCoin"}

[1] [:a :b {:site "so"}]

[0 :cat] "Garfield"

...

问题:

上面的问题是否有内置解决方案? 其中处理函数接收节点和从根节点到该节点的路径?

谢谢!

可能的解决方案

(基于fl00r的建议)

(defn pathwalk [f cur-path node]
  (let [f1 #(pathwalk f (conj cur-path %1) %2)]
    (f cur-path node)
    (cond
      (map? node) (map #(apply f1 %) node)
      (or (vector? node) (list? node)) (keep-indexed f1 node))))

2
这是一个略微不同的问题,但可能对您有趣 https://dev59.com/rpDea4cB1Zd3GeqPhuGv - fl00r
@fl00r:非常有用;我刚刚根据那个写了一个解决方案。 - eav db
1个回答

2
我想你也希望'pathwalk'从函数f中返回类似于clojure.walk/prewalk的东西,而不是依赖于副作用?例如:
(prewalk #(if (= :a %) :c %) [:a :b])
=>
[:c :b]

如果是的话,你可以这样做:
(defn pathwalk [f path e]
  (let [e' (f path e)]
    (cond
      (map? e')  (->> e'
                      (map (fn [[k x]] [k (pathwalk f (conj path k) x)]))
                      (into (empty e')))
      (coll? e') (->> e'
                      (map-indexed (fn [i x] (pathwalk f (conj path i) x)))
                      (into (empty e')))
      :else      e')))

这是一个测试运行:

(pathwalk #(do
             (println %1 %2)
             (if (= :a %2)
               :c
               %2))
          []
          [ {:cat "Garfield", :dog "DogeCoin"} [:a :b {:site "so"}]])

它将会打印:

[] [{:cat Garfield, :dog DogeCoin} [:a :b {:site so}]]
[0] {:cat Garfield, :dog DogeCoin}
[0 :cat] Garfield
[0 :dog] DogeCoin
[1] [:a :b {:site so}]
[1 0] :a
[1 1] :b
[1 2] {:site so}
[1 2 :site] so

以下数据将从该函数返回:
[{:cat "Garfield", :dog "DogeCoin"} [:c :b {:site "so"}]]

对于这个特定的例子,目标是副作用(即构建一个扁平化的[[path value]]列表),但是,是的,你是正确的,在一般情况下,还应该支持纯函数。谢谢! - eav db

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接