Clojure转换后续数据的方式是什么?

时间:2019-04-22 13:15:44

标签: clojure

所以我今天刚和Clojure一起玩过。

使用此数据,

(def test-data
  [{:id 35462, :status "COMPLETED", :p 2640000, :i 261600}
   {:id 35462, :status "CREATED", :p 240000, :i 3200}
   {:id 57217, :status "COMPLETED", :p 470001, :i 48043}
   {:id 57217, :status "CREATED", :p 1409999, :i 120105}])

然后使用

转换上面的数据
(as-> test-data input
      (group-by :id input)
      (map (fn [x] {:id (key x)
                    :p  {:a (as-> (filter #(= (:status %) "COMPLETED") (val x)) tmp
                                  (into {} tmp)
                                  (get tmp :p))
                         :b (as-> (filter #(= (:status %) "CREATED") (val x)) tmp
                                  (into {} tmp)
                                  (get tmp :p))}
                    :i  {:a (as-> (filter #(= (:status %) "COMPLETED") (val x)) tmp
                                  (into {} tmp)
                                  (get tmp :i))
                         :b (as-> (filter #(= (:status %) "CREATED") (val x)) tmp
                                  (into {} tmp)
                                  (get tmp :i))}})
           input)
      (into [] input))

要生产

[{:id 35462, :p {:a 2640000, :b 240000}, :i {:a 261600, :b 3200}}
 {:id 57217, :p {:a 470001, :b 1409999}, :i {:a 48043, :b 120105}}]

但是我感觉我的代码不是“ Clojure方式” 。所以我的问题是,“ Clojure方式” 是什么可以实现我的生产成果?

4 个答案:

答案 0 :(得分:3)

proxy_pass_header Server; 可以正常工作时,使用as->才能使我脱颖而出的唯一事情是,有些工作重复进行,并且有破坏性的机会:

->>

但是,将那些(defn aggregate [[id values]] (let [completed (->> (filter #(= (:status %) "COMPLETED") values) (into {})) created (->> (filter #(= (:status %) "CREATED") values) (into {}))] {:id id :p {:a (:p completed) :b (:p created)} :i {:a (:i completed) :b (:i created)}})) (->> test-data (group-by :id) (map aggregate)) => ({:id 35462, :p {:a 2640000, :b 240000}, :i {:a 261600, :b 3200}} {:id 57217, :p {:a 470001, :b 1409999}, :i {:a 48043, :b 120105}}) 的值(本身就是地图)倒入地图对我来说似乎很可疑。这将创建一个万不得已的方案,其中测试数据的顺序会影响输出。尝试以下操作以查看filter的不同顺序如何影响输出:

test-data

答案 1 :(得分:2)

这是一个非常奇怪的转换,键似乎有点随意,并且很难从n = 2泛化(或者实际上很难知道n是否大于2)。

我将使用功能分解来排除一些共同点并获得一定的吸引力。首先,让我们将状态转换为密钥...

(def status->ab {"COMPLETED" :a "CREATED" :b})

然后,有了这个,我想要一种简单的方法来使“肉”脱离子结构。在这里,对于数据中的给定键,我将提供该键的包围图的内容以及给定的组结果。

(defn subgroup->subresult [k subgroup]
    (apply array-map (mapcat #(vector (status->ab (:status %)) (k %)) subgroup)))

这样,主变压器变得更容易处理了

(defn group->result [group] 
        {
         :id (key group)
         :p (subgroup->subresult :p (val group))
         :i (subgroup->subresult :i (val group))})

我不会考虑在:p和:i上进行概括-如果您有两个以上的键,那么也许我会生成k->子组结果的映射并进行某种归约合并。无论如何,我们有一个答案:

(map group->result (group-by :id test-data))
;; =>
({:id 35462, :p {:b 240000, :a 2640000}, :i {:b 3200, :a 261600}}
 {:id 57217, :p {:b 1409999, :a 470001}, :i {:b 120105, :a 48043}})

答案 2 :(得分:1)

没有一个“ Clojure方式” (我想您的意思是功能方式),这取决于您如何分解问题。

这是我要做的事情:

(->> test-data
     (map (juxt :id :status identity))
     (map ->nested)
     (apply deep-merge)
     (map (fn [[id m]]
            {:id id
             :p  (->ab-map m :p)
             :i  (->ab-map m :i)})))

;; ({:id 35462, :p {:a 2640000, :b 240000}, :i {:a 261600, :b 3200}}
;;  {:id 57217, :p {:a 470001, :b 1409999}, :i {:a 48043, :b 120105}})

如您所见,我使用了一些功能,这是分步说明:

  1. 提取索引键(id + status),并将地图本身提取为矢量
(map (juxt :id :status identity) test-data)
;; ([35462 "COMPLETED" {:id 35462, :status "COMPLETED", :p 2640000, :i 261600}]
;;  [35462 "CREATED" {:id 35462, :status "CREATED", :p 240000, :i 3200}]
;;  [57217 "COMPLETED" {:id 57217, :status "COMPLETED", :p 470001, :i 48043}]
;;  [57217 "CREATED" {:id 57217, :status "CREATED", :p 1409999, :i 120105}])
  1. 转换为嵌套地图(id,然后转换为状态)
(map ->nested *1)
;; ({35462 {"COMPLETED" {:id 35462, :status "COMPLETED", :p 2640000, :i 261600}}}
;;  {35462 {"CREATED" {:id 35462, :status "CREATED", :p 240000, :i 3200}}}
;;  {57217 {"COMPLETED" {:id 57217, :status "COMPLETED", :p 470001, :i 48043}}}
;;  {57217 {"CREATED" {:id 57217, :status "CREATED", :p 1409999, :i 120105}}})
  1. 按ID合并嵌套地图
(apply deep-merge *1)
;; {35462
;;  {"COMPLETED" {:id 35462, :status "COMPLETED", :p 2640000, :i 261600},
;;   "CREATED" {:id 35462, :status "CREATED", :p 240000, :i 3200}},
;;  57217
;;  {"COMPLETED" {:id 57217, :status "COMPLETED", :p 470001, :i 48043},
;;   "CREATED" {:id 57217, :status "CREATED", :p 1409999, :i 120105}}}
  1. 对于属性:p:i,根据状态映射到:a:b
(->ab-map {"COMPLETED" {:id 35462, :status "COMPLETED", :p 2640000, :i 261600},
           "CREATED" {:id 35462, :status "CREATED", :p 240000, :i 3200}}
          :p)
;; => {:a 2640000, :b 240000}

以下是我使用的一些辅助功能:

(defn ->ab-map [m k]
  (zipmap [:a :b]
          (map #(get-in m [% k]) ["COMPLETED" "CREATED"])))

(defn ->nested [[k & [v & r :as t]]]
  {k (if (seq r) (->nested t) v)})

(defn deep-merge [& xs]
  (if (every? map? xs)
    (apply merge-with deep-merge xs)
    (apply merge xs)))

答案 3 :(得分:1)

我将更像下面这样处理它,因此它可以为每个:id值处理任意数量的条目。当然,可以有很多变化。

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [tupelo.core :as t] ))

(dotest
  (let [test-data [{:id 35462, :status "COMPLETED", :p 2640000, :i 261600}
                   {:id 35462, :status "CREATED", :p 240000, :i 3200}
                   {:id 57217, :status "COMPLETED", :p 470001, :i 48043}
                   {:id 57217, :status "CREATED", :p 1409999, :i 120105}]
        d1        (group-by :id test-data)
        d2        (t/forv [[id entries] d1]
                    {:id         id
                     :status-all (mapv :status entries)
                     :p-all      (mapv :p entries)
                     :i-all      (mapv :i entries)})]
    (is= d1
      {35462
       [{:id 35462, :status "COMPLETED", :p 2640000, :i 261600}
        {:id 35462, :status "CREATED", :p 240000, :i 3200}],
       57217
       [{:id 57217, :status "COMPLETED", :p 470001, :i 48043}
        {:id 57217, :status "CREATED", :p 1409999, :i 120105}]})

    (is= d2 [{:id         35462,
              :status-all ["COMPLETED" "CREATED"],
              :p-all      [2640000 240000],
              :i-all      [261600 3200]}
             {:id         57217,
              :status-all ["COMPLETED" "CREATED"],
              :p-all      [470001 1409999],
              :i-all      [48043 120105]}])
    ))