我们说我有一张这样的地图(m
):
(def m {:a 1 :b 2 :c {:d 3 :e 4} :e { ... } ....})
我想创建一个仅包含来自:a
的{{1}},:b
和:d
的新地图,即结果应为:
m
我知道我可以使用{:a 1 :b 2 :d 3}
轻松获取select-keys
和:a
:
:b
但是,获得(select-keys m [:a :b])
的好方法是什么?我正在寻找这样的事情:
:d
Clojure中是否存在这样的功能或推荐的方法是什么?
答案 0 :(得分:7)
在纯粹的Clojure中,我会这样做:
(defn select-keys* [m paths]
(into {} (map (fn [p]
[(last p) (get-in m p)]))
paths))
(select-keys* m [[:a] [:b] [:c :d]]) ;;=> {:a 1, :b 2, :d 3}
我更喜欢保持路径的类型是规则的,因此所有路径都有一系列键。在clojure.spec
中,这将显示为
(s/def ::nested-map (s/map-of keyword?
(s/or :num number? :map ::nested-map)))
(s/def ::path (s/coll-of keyword?))
(s/fdef select-keys*
:args (s/cat :m ::nested-map
:paths (s/coll-of ::path)))
答案 1 :(得分:2)
我不知道这样的功能是Clojure的一部分。你可能不得不自己写。我想出了这个:
(defn select-keys* [m v]
(reduce
(fn [aggregate next]
(let [key-value (if (vector? next)
[(last next)
(get-in m next)]
[next
(get m next)])]
(apply assoc aggregate key-value)))
{}
v))
答案 2 :(得分:2)
作为替代方案,您可以对函数使用destruct,例如:
{{1}}
答案 3 :(得分:0)
要求路径为向量,以便您可以使用peek
(比last
快得多)。减少这样的路径:
(defn select-keys* [m paths]
(reduce (fn [r p] (assoc r (peek p) (get-in m p))) {} paths))
(select-keys* m [[:a] [:b] [:c :d]]) ;;=> {:a 1, :b 2, :d 3}
当然,这假设您的所有终端密钥都是唯一的。