从值到关键字的数据转换

问题描述 投票:0回答:3

假设我有以下数据:

({:year 2023, :month 4, :type TypeA, :cat CatA, :amount 62.5} 
 {:year 2023, :month 4, :type TypeB, :cat CatB, :amount 45.25} 
 {:year 2023, :month 4, :type TypeC, :cat CatA, :amount 40.0} 
 {:year 2023, :month 5, :type TypeA, :cat CatA, :amount 52.75} 
 {:year 2023, :month 5, :type TypeC, :cat CatA, :amount 14.0})

我想按类型或按猫将其转换为以下内容:

({:year 2023, :month 4, :typeA 62.5, :typeB 42.25, :typeC 40.0}
 {:year 2023, :month 5, :typeA 52.75, :typeB 0, :typeC 14.0}}

或猫:

({:year 2023, :month 4, :catA 102.5, :catB 42.25}
 {:year 2023, :month 5, :catA 52.75, :catB 14.0}}

我对不同的和嵌套的地图进行了一些尝试,但没有找到有效的解决方案。

奖金: 类型和猫应该是灵活的,通过名称硬编码来引用它们是不安全的。

clojure
3个回答
3
投票

另外,一次通过(我猜是一个更简单的选项):

(defn process [k data]
  (vals (reduce 
         #(let [y-m (select-keys %2 [:year :month])]
            (update % y-m (fnil assoc y-m) (keyword (k %2)) (:amount %2)))
         nil 
         data)))
user> (process :type data)
;;=> ({:year 2023, :month 4, :TypeA 62.5, :TypeB 45.25, :TypeC 40.0}
;;   {:year 2023, :month 5, :TypeA 52.75, :TypeC 14.0})

user> (process :cat data)
;;=> ({:year 2023, :month 4, :CatA 40.0, :CatB 45.25}
;;    {:year 2023, :month 5, :CatA 14.0})

1
投票

结果似乎已经很接近了

(let [data '({:year 2023, :month 4, :type TypeA, :cat CatA, :amount 62.5}
             {:year 2023, :month 4, :type TypeB, :cat CatB, :amount 45.25}
             {:year 2023, :month 4, :type TypeC, :cat CatA, :amount 40.0}
             {:year 2023, :month 5, :type TypeA, :cat CatA, :amount 52.75}
             {:year 2023, :month 5, :type TypeC, :cat CatA, :amount 14.0})
      key-fields [:year :month]
      k-field :cat
      ;k-field :type
      v-field :amount]
  (->> data
       (group-by #(select-keys % key-fields))
       (mapv (fn [[k ms]]
               (reduce (fn [k m]
                         (let [;; Not sure if you need to make the first character lower-case here.
                               f (keyword (k-field m))]
                           (assoc k f (v-field m))))
                       k ms)))))

它不会为缺失值添加零,但我认为通常最好不要添加它们。相反,此代码的客户可以决定如何处理它们。


0
投票

相同,但带有换能器:

(defn transform [key]
    (xf/into-by-key [] (fn-> (select-keys [:year :month])) identity into
        (comp
            (xf/sort-by key)
            (xf/into-by-key [] (comp keyword key) :amount (xf/reduce +)))))

(into [] (xf/transjuxt {:type (transform :type)
                        :cat  (transform :cat)}) data)
=>
[{:type 
       [{:year 2023, :month 4, :TypeA 62.5, :TypeB 45.25, :TypeC 40.0}
         {:year 2023, :month 5, :TypeA 52.75, :TypeC 14.0}],
  :cat 
       [{:year 2023, :month 4, :CatA 102.5, :CatB 45.25} 
        {:year 2023, :month 5, :CatA 66.75}]}]

xf
[net.cgrand.xforms :as xf]

© www.soinside.com 2019 - 2024. All rights reserved.