Fork me on GitHub
#specter
<
2024-02-02
>
wei07:02:20

last question for now 🙏 can you help me combine this into one path? i want to filter on cost type :labor , then sum labor hours by category. getting tripped up on the group-by.

(def -line-items
    [{:line-item/cost-type :labor
      :line-item/category "Piping"
      :labor/total-hours 5}
     {:line-item/cost-type :labor
      :line-item/category "Sheet Metal"
      :labor/total-hours 8}
     {:line-item/cost-type :labor
      :line-item/category "Piping"
      :labor/total-hours 7}
     {:line-item/cost-type :material
      :line-item/category "Piping"
      :material/cost 500}
     {:line-item/cost-type :material
      :line-item/category "Sheet Metal"
      :material/cost 300}
     {:line-item/cost-type :labor
      :line-item/category "Sheet Metal"
      :labor/total-hours 4}])

  ;; filter on cost type :labor, then sum labor hours by category
  (->> -line-items
       (sp/select [sp/ALL (comp #{:labor} :line-item/cost-type)])
       (group-by :line-item/category)
       (sp/transform [sp/MAP-VALS (sp/view #(sp/select [sp/ALL :labor/total-hours number?] %))]
                     #(reduce + 0 %)))
  ;; => {"Piping" 12, "Sheet Metal" 12}
i tried copying this from examples but i'm misunderstanding how group-by-nav works.
(sp/defnav group-by-view [key]
    (select* [this structure next-fn]
             (next-fn (group-by key structure)))
    (transform* [this structure next-fn]
                (next-fn (group-by key structure))))

  (defn group-by-nav [f] (sp/path (group-by-view f) sp/ALL sp/LAST))

  (->> -line-items
       (sp/transform [sp/ALL (comp #{:labor} :line-item/cost-type)
                      (group-by-nav :line-item/category)
                      sp/MAP-VALS (sp/view #(sp/select [sp/ALL :labor/total-hours number?] %))]
                     #(reduce + 0 %)))

wei23:02:46

nevermind, i found a better approach that doesn't involve group-by. seems like group-by can be a bit of an antipattern when applying specter

wei17:02:01

just for completeness, i came up with a solution that uses group-by-view. any suggestions would be appreciated.

(sp/transform [(group-by-view :line-item/category)
               sp/ALL
               (sp/collect-one sp/FIRST)
               (sp/collect
                sp/LAST
                sp/ALL
                (comp #{:labor} :line-item/cost-type)
                :labor/total-hours)]
              (fn [k v v2]
                [k (reduce + 0 v)])
              -line-items)