在Clojure中计算嵌套地图地图的某些属性的惯用方法是什么?
鉴于以下数据结构:
(def x {
:0 {:attrs {:attributes {:dontcare "something"
:1 {:attrs {:abc "some value"}}}}}
:1 {:attrs {:attributes {:dontcare "something"
:1 {:attrs {:abc "some value"}}}}}
:9 {:attrs {:attributes {:dontcare "something"
:5 {:attrs {:xyz "some value"}}}}}})
我如何产生所需的输出:
(= (count-attributes x) {:abc 2, :xyz 1})
这是我迄今为止的最大努力:
(defn count-attributes
[input]
(let [result (for [[_ {{attributes :attributes} :attrs}] x
:let [v (into {} (remove (comp not :attrs) (vals attributes)))]]
(:attrs v))]
(frequencies result)))
产生以下内容:
{{:abc "some value"} 2, {:xyz "some value"} 1}
答案 0 :(得分:1)
我喜欢使用线程构建这样的函数,因此步骤更容易阅读
user> (->> x
vals ; first throw out the keys
(map #(get-in % [:attrs :attributes])) ; get the nested maps
(map vals) ; again throw out the keys
(map #(filter map? %)) ; throw out the "something" ones.
flatten ; we no longer need the sequence sequences
(map vals) ; and again we don't care about the keys
flatten ; the map put them back into a list of lists
frequencies) ; and then count them.
{{:abc "some value"} 2, {:xyz "some value"} 1}
(remove (comp not :attrs)
与select-keys
很相似
for [[_ {{attributes :attributes} :attrs}]
提醒我get-in
答案 1 :(得分:1)
我发现tree-seq
对这些情况非常有用:
(frequencies (filter #(and (map? %) (not-any? map? (vals %))) (tree-seq map? vals x)))