Vector 基于密钥将向量拆分为向量向量

Vector 基于密钥将向量拆分为向量向量,vector,clojure,functional-programming,lisp,Vector,Clojure,Functional Programming,Lisp,我有一个单独的对象向量,我想将其转换为对象向量向量,其中子向量中的每个对象对于特定成员具有相同的值。e、 g [{:sku "105"}, {:sku "105"}, {:sku "120"}] 变成 [[{:sku "105"}, {:sku "105"}], [{:sku "120"}]] 我试图掌握函数式的思维方式,但我很确定我还没有掌握,因为我的代码看起来相当笨拙。但到目前为止,我得到的是: (defn separate-by-invoice [original-invoices]

我有一个单独的对象向量,我想将其转换为对象向量向量,其中子向量中的每个对象对于特定成员具有相同的值。e、 g

[{: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)))

基本上,我的想法是,我形成一个向量,temp invoices,用相同发票号的所有条目填充它,然后一旦我们得到所有条目,将该向量插入最终向量,并返回该值。但最终发票似乎总是一个空向量。我做错了什么?clojure通常是如何做到这一点的?

让我们将其分为两个子问题:

user> (def x [{:sku "105"}, {:sku "105"}, {:sku "120"}])
#<Var@18bc9d90: [{: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"}]]

您可以使用和的组合(如果您希望得到向量):

可选使用以提高可读性:

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

您需要使用
分组依据
功能:

(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)))

非常感谢。这比我想象的要容易得多。我建议不要使用
(mapv second)
函数,而是使用
vals
函数从地图中提取所有值。这一点很好。但您还需要使用
vec
将其包装起来,以防您需要的是精确的vector(而不是其他seq)
(->> data
  (group-by :sku)
  (mapv second))
(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)))