有条件地重命名列表中的键并转换为地图?

时间:2019-04-24 04:12:32

标签: clojure

是否有一种简单的方法可以将键值列表转换为映射,同时还可以有条件地重命名键?

示例:

 [{:count 4, :happened "true"} {:count 1, :happened "false"}]

转换为:

{:happened-count: 4, :didnt-happen-count: 1}

我有点接近:

user=> (def foo [{:count 4, :happened "true"} {:count 1, :happened "false"}])

user=> (into {} (map (juxt :happened :count) foo))
{"true" 4, "false" 1}

edit:这可行,但是很难看。希望有更好的东西:

(clojure.set/rename-keys (into {} (map (juxt :happened :count) foo)) {"true" :happened-count "false" :didnt-happen-count})

3 个答案:

答案 0 :(得分:3)

我宁愿使用简单归约法

(def mapping {"true" :happened-count "false" :didnt-happen-count})

(reduce #(assoc % (-> %2 :happened mapping) (:count %2)) {} data)

;;=> {:happened-count 4, :didnt-happen-count 1}

答案 1 :(得分:2)

如果有帮助,可以使用->>宏将转换视为管道:

(->> [{:count 4, :happened "true"} {:count 1, :happened "false"}]
     (map (juxt :happened :count))
     (into {})
     (clojure.set/rename-keys {"true"  :happened-count
                               "false" :didnt-happen-count}))

例如首先提取值,然后将它们分组到新地图中,然后重命名键

答案 2 :(得分:1)

有百万种方法可以解决这样的问题。我喜欢明确说明这些步骤。这是我的想法:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(dotest
  (let [data       [{:count 4, :happened "true"}
                    {:count 1, :happened "false"}
                    {:count 5, :happened "true"}
                    {:count 3, :happened "false"}]
        data-split (group-by :happened data)
        sum-count  (fn [recs]
                     (reduce +
                       (mapv :count recs)))
        result     {:happened-num     (sum-count (get data-split "true"))
                    :didnt-happen-num (sum-count (get data-split "false"))}]
    (is= data-split
      {"true"  [{:count 4, :happened "true"}
                {:count 5, :happened "true"}],
       "false" [{:count 1, :happened "false"}
                {:count 3, :happened "false"}]} )
    (is= result {:happened-num 9, :didnt-happen-num 4})))

我为真假案例添加了多条记录,因为这似乎是一个更典型的用例。