如何在Clojure中更扁平的数据结构中获得相同的val?

时间:2013-05-26 01:37:12

标签: clojure

所以我有这个数据结构:

(def params
  {:site1
    {:index-element
       {:date  "2012-10-10"
        :title "Hello"}
     :subpage-element
        {:time     "9:00"
         :location "Toronto"}}
   :site2 …})

我想将其更改为更扁平的数据结构

(def new-params  
  {1
    {:name     :site1
     :date     ["2012-10-10" :index-element]
     :title    ["Hello"      :index-element] 
     :time     ["9:00"       :subpage-element]
     :location ["Toronto"    :subpage-element]}
   2 …})

要获得我想要的结果:

(mapv #(-> params % :index-element vals)
      (keys params))

我如何使用new-params获得相同的结果?

2 个答案:

答案 0 :(得分:4)

以下是三种方式:

;;; 1.
(reduce-kv (fn [res siteno m]
             (->> (vals m)
                  (filter #(and (vector? %)
                                (identical? :index-element (peek %))))
                  (map first)
                  (conj res)))
           []
           new-params)

;;; 2.
(->> new-params
     (vals)
     (map vals)
     (map (partial filter #(and (vector? %)
                                (identical? :index-element (peek %)))))
     (mapv (partial map first)))

;;; 3. (better than 2., but only for Clojure >= 1.5)
(require '[clojure.core.reducers :as r])

(->> new-params
     (vals)
     (r/map vals)
     (r/map (partial filter #(and (vector? %)
                                  (identical? :index-element (peek %)))))
     (r/map (partial map first))
     (into []))

切换到mapv(在1.中的匿名函数中,在2.& 3中的最后partial中)以获取向量的向量而不是惰性seq的向量(和从而使内部集合的构建变得非常惰性 - 这可能很有意义。)

原始数据结构实际上更适合这种访问;没有避免使用更平坦的地图进行线性搜索。这可能是性能问题,具体取决于访问模式和实际数据。

答案 1 :(得分:3)

一个选项是使用for(在恕我直言中使其更具可读性):

(->> (for [[i site] new-params]
       (for [ [s-k s-v] site
              :when (not= s-k :name)
              :let [[k [v v-k]] [s-k s-v]]
              :when (= v-k :index-element)]
         v))
     (into []))