使用specter进行递归映射查询

jwi*_*ndy 6 clojure specter

是否有一种简单的方法可以收集满足谓词的所有结构?

(./pull '[com.rpl/specter "1.0.0"])

(use 'com.rpl.specter)

(def data {:items [{:name "Washing machine"
                    :subparts [{:name "Ballast" :weight 1}
                               {:name "Hull"    :weight 2}]}]})



(reduce + (select [(walker :weight) :weight] data))
;=> 3

(select [(walker :name) :name] data)
;=> ["Washing machine"]
Run Code Online (Sandbox Code Playgroud)

我们怎样才能获得所有的价值:名称,包括["镇流器""船体"]?

Mic*_*zyk 5

这是一种方法,使用recursive-pathstay-then-continue来完成实际工作。(如果省略:name路径参数中的最后一个select,您将获得完整的 \xe2\x80\x9citem / 部分映射 \xe2\x80\x9d 而不仅仅是字符串:name。)

\n\n
(def data\n  {:items [{:name "Washing machine"\n            :subparts [{:name "Ballast" :weight 1}\n                       {:name "Hull" :weight 2}]}]})\n\n(specter/select\n  [(specter/recursive-path [] p\n     [(specter/walker :name) (specter/stay-then-continue [:subparts p])])\n   :name]\n  data)\n;= ["Washing machine" "Ballast" "Hull"]\n
Run Code Online (Sandbox Code Playgroud)\n\n

更新:为了回答下面的评论,这里是上面的一个版本,它下降到树的任意分支,而不是仅下降到:subparts任何给定节点的分支,排除:name(这是树中值的键)我们想要提取并且本身不应该被视为分支点):

\n\n
(specter/select\n  [(specter/recursive-path [] p\n     [(specter/walker :name)\n      (specter/stay-then-continue\n        [(specter/filterer #(not= :name (key %)))\n         (specter/walker :name)\n         p])])\n   :name]\n  ;; adding the key `:subparts` with the value [{:name "Foo"}]\n  ;; to the "Washing machine" map to exercise the new descent strategy\n  (assoc-in data [:items 0 :subparts2] [{:name "Foo"}]))\n\n;= ["Washing machine" "Ballast" "Hull" "Foo"]\n
Run Code Online (Sandbox Code Playgroud)\n