Dictionary Clojure-与小径同行
我正在寻找一个与中类似的函数,该函数有一个Dictionary Clojure-与小径同行,dictionary,data-structures,clojure,clojurescript,Dictionary,Data Structures,Clojure,Clojurescript,我正在寻找一个与中类似的函数,该函数有一个内部函数作为参数: 不是键和值,就像clojure.walk/walk函数一样 但是从顶级数据结构访问值所需的键向量 递归遍历所有数据 例如: ;; not good since it takes `[k v]` as argument instead of `[path v]`, and is not recursive. user=> (clojure.walk/walk (fn [[k v]] [k (* 10 v)]) identity
内部
函数作为参数:
- 不是键和值,就像clojure.walk/walk函数一样
- 但是从顶级数据结构访问值所需的键向量
- 递归遍历所有数据
;; not good since it takes `[k v]` as argument instead of `[path v]`, and is not recursive.
user=> (clojure.walk/walk (fn [[k v]] [k (* 10 v)]) identity {:a 1 :b {:c 2}})
;; {:a 10, :c 30, :b 20}
;; it should receive as arguments instead :
[[:a] 1]
[[:b :c] 2]
注:
- 它也应该使用数组,使用键0、1、2。。。(就像在
进入
中一样)
- 如果允许简化代码,我并不真正关心
参数outer
- 首先将嵌套结构转换为以路径为键的字典,并将值
- 然后将内部函数映射到外部函数,或使用外部函数进行缩减
;; Helper function to have vector's indexes work like for get-in
(defn- to-indexed-seqs [coll]
(if (map? coll)
coll
(map vector (range) coll)))
;; Flattening the tree to a dict of (path, value) pairs that I can map over
;; user> (flatten-path [] {:a {:k1 1 :k2 2} :b [1 2 3]})
;; {[:a :k1] 1, [:a :k2] 2, [:b 0] 1, [:b 1] 2, [:b 2] 3}
(defn- flatten-path [path step]
(if (coll? step)
(->> step
to-indexed-seqs
(map (fn [[k v]] (flatten-path (conj path k) v)))
(into {}))
[path step]))
;; Some final glue
(defn path-walk [f coll]
(->> coll
(flatten-path [])
(map #(apply f %))))
;; user> (println (clojure.string/join "\n" (path-walk #(str %1 " - " %2) {:a {:k1 1 :k2 2} :b [1 2 3]})))
;; [:a :k1] - 1
;; [:a :k2] - 2
;; [:b 0] - 1
;; [:b 1] - 2
;; [:b 2] - 3
结果是Stuart Halloway发表了一篇文章,这篇文章可能有一些用处(它使用了一个协议,这也使得它具有可扩展性): 注意:在我的情况下,我也可以使用,因此如果您正在阅读此文章,您可能还想查看它。还有
在您的示例中,数据不应该是
{[:a:k1]1、[:a:k2]2、[:b0]1、[:b1]2、[:b2]3}
?哦,真的!to索引seqs中有一个错误,应该是:(映射向量(范围)coll)而不是:(映射向量coll(范围))我将更新我的答案:)谢谢!我接受了您的回答,但仍然希望有一个不需要枚举路径的解决方案(我的用例是需要一些转换的数据库迁移)。
(ns user)
(def app
"Intenal Helper"
(fnil conj []))
(defprotocol PathSeq
(path-seq* [form path] "Helper for path-seq"))
(extend-protocol PathSeq
java.util.List
(path-seq*
[form path]
(->> (map-indexed
(fn [idx item]
(path-seq* item (app path idx)))
form)
(mapcat identity)))
java.util.Map
(path-seq*
[form path]
(->> (map
(fn [[k v]]
(path-seq* v (app path k)))
form)
(mapcat identity)))
java.util.Set
(path-seq*
[form path]
(->> (map
(fn [v]
(path-seq* v (app path v)))
form)
(mapcat identity)))
java.lang.Object
(path-seq* [form path] [[form path]])
nil
(path-seq* [_ path] [[nil path]]))
(defn path-seq
"Returns a sequence of paths into a form, and the elements found at
those paths. Each item in the sequence is a map with :path
and :form keys. Paths are built based on collection type: lists
by position, maps by key, and sets by value, e.g.
(path-seq [:a [:b :c] {:d :e} #{:f}])
({:path [0], :form :a}
{:path [1 0], :form :b}
{:path [1 1], :form :c}
{:path [2 :d], :form :e}
{:path [3 :f], :form :f})
"
[form]
(map
#(let [[form path] %]
{:path path :form form})
(path-seq* form nil)))
(comment
(path-seq [:a [:b :c] {:d :e} #{:f}])
;; finding nils hiding in data structures:
(->> (path-seq [:a [:b nil] {:d :e} #{:f}])
(filter (comp nil? :form)))
;; finding a nil hiding in a Datomic transaction
(->> (path-seq {:db/id 100
:friends [{:firstName "John"}
{:firstName nil}]})
(filter (comp nil? :form)))
)
(def node (:b (first (root :a))))
(= node {:c 1}) ;; => true
(c/context node) ;; => [:a 0 :b]