2016-03-08 91 views
2

我有對象的單一載體的載體到載體的載體,我想變換成對象,其中在所述子向量的每個對象具有特定成員的值相同的矢量的矢量。例如分裂基於關鍵

[{:sku "105"}, {:sku "105"}, {:sku "120"}] 

成爲

[[{:sku "105"}, {:sku "105"}], [{:sku "120"}]] 

我試圖把握思維功能性的方式,但我敢肯定,我現在還沒有,因爲我的代碼看起來很笨拙。但這裏是我到目前爲止有:

(defn separate-by-invoice [original-invoices] 
    (let [sorted-invoices (sort-by :invoice-number original-invoices)] 
    (def temp-invoices []) 
    (reduce (fn [final-invoices invoice] 
     (let [prev-invoice-number (get-in (last temp-invoices) [:invoice-number]) 
      invoice-number (get-in invoice [:invoice-number])] 
     (if (= prev-invoice-number invoice-number) 
      (do 
      (into temp-invoices invoice)) 
      (do 
      (into final-invoices temp-invoices) 
      (def temp-invoices []) 
      (into temp-invoices invoice)))) 
     final-invoices) 
     [] 
     sorted-invoices))) 

基本上,我的想法是,我形成一個矢量,溫度,發票,並與所有具有相同的發票編號的條目的填充,然後一旦我們得到所有這些,將該向量插入最終向量,然後返回該值。但是,似乎最終發票總是空的矢量。我究竟做錯了什麼?這是如何通常在clojure中完成的?

回答

5

讓分解成兩個子問題的:

user> (def x [{:sku "105"}, {:sku "105"}, {:sku "120"}]) 
#<[email protected]: [{:sku "105"} {:sku "105"} {:sku "120"}]> 

第一組的數據等一起:

user> (sort-by :sku x) 
({:sku "105"} {:sku "105"} {:sku "120"}) 

然後在每次改變它拆分:

user> (partition-by :sku (sort-by :sku x)) 
(({:sku "105"} {:sku "105"}) ({:sku "120"})) 

其可以還採用螺紋式的,使流動更容易被寫爲:

user> (->> x 
      (sort-by :sku) 
      (partition-by :sku) 
      (mapv vec)) 
[[{:sku "105"} {:sku "105"}] [{:sku "120"}]] 
+0

非常感謝。這比我想象的要容易得多。 – kennycoc

3

您可以使用的group-bymapv組合(如果你想獲得向量作爲結果):

(def data [{:sku "105"}, {:sku "105"}, {:sku "120"}]) 
(group-by :sku data) 
;; => {"105" [{:sku "105"} {:sku "105"}], "120" [{:sku "120"}]} 

(mapv second (group-by :sku data)) 
;; => [[{:sku "105"} {:sku "105"}] [{:sku "120"}]] 

可以選擇使用threading爲更好的可讀性:

(->> data 
    (group-by :sku) 
    (mapv second)) 
+2

而不是'(mapv第二)'我建議只使用'vals'函數提取所有的值從地圖。 –

+0

好點。但你需要另外用'vec'包裝它,以防你需要精確的矢量(並且沒有其他seq) – OlegTheCat

1

您需要使用group-by功能:

(ns tst.clj.core 
    (:use clj.core 
     clojure.test 
     tupelo.core)) 

(def input [ {:id 1 :sku 105} 
       {:id 2 :sku 105} 
       {:id 3 :sku 120} ]) 

(def result [ [ {:id 1 :sku 105} 
        {:id 2 :sku 105} ] 
       [ {:id 3 :sku 120} ] ]) 

(deftest t-separate-by-sku 
    ; the result of 'group-by' is a map keyed by the grouping value 
    ; (the sku in this case) 
    (is (= (group-by :sku input) 
     { 105 [{:id 1, :sku 105} {:id 2, :sku 105}], 
      120 [{:id 3, :sku 120}] })) 
    ; we do not care about the grouping value, so just extract 
    ; the values from the map with 'vals' 
    (is (= (vals (group-by :sku input)) 
     result)))