根据键将向量拆分为向量的向量
Splitting a vector into vector of vectors based on key
我有一个对象向量,我想将其转换为对象向量向量,其中子向量中的每个对象对于特定成员具有相同的值。例如
[{: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,并用具有相同发票编号的所有条目填充它,然后一旦我们得到所有条目,将该向量插入最终-vector,并且 return 该值。但相反,final-invoices 似乎始终是一个空向量。我究竟做错了什么?这在 clojure 中通常是如何完成的?
让我们将其分解为两个子问题:
user> (def x [{:sku "105"}, {:sku "105"}, {:sku "120"}])
#<Var@18bc9d90: [{: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"}]]
您可以使用 group-by
and mapv
的组合(以防您希望得到矢量结果):
(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))
您需要使用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)))
我有一个对象向量,我想将其转换为对象向量向量,其中子向量中的每个对象对于特定成员具有相同的值。例如
[{: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,并用具有相同发票编号的所有条目填充它,然后一旦我们得到所有条目,将该向量插入最终-vector,并且 return 该值。但相反,final-invoices 似乎始终是一个空向量。我究竟做错了什么?这在 clojure 中通常是如何完成的?
让我们将其分解为两个子问题:
user> (def x [{:sku "105"}, {:sku "105"}, {:sku "120"}])
#<Var@18bc9d90: [{: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"}]]
您可以使用 group-by
and mapv
的组合(以防您希望得到矢量结果):
(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))
您需要使用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)))