Skip to content

Instantly share code, notes, and snippets.

@jplaza
Created October 21, 2023 02:52
Show Gist options
  • Save jplaza/dfa624a8f9c9effc8c5edee74c99a6d2 to your computer and use it in GitHub Desktop.
Save jplaza/dfa624a8f9c9effc8c5edee74c99a6d2 to your computer and use it in GitHub Desktop.
Aggregate data in the form of a list of hash maps in Clojure. Inspired by SQL GROUP BY and aggregate functions like SUM and MAX
(defn aggregate-data
"data - collection of hash-maps to aggregate
group-key - vector of keys to group hash-maps
aggregates - vector of vectors of key, aggregate fn and optionally a new
name for this key e.g.
[[+ :amount :stock]
[max :date :latest-tx-date]]
Aggregate functions receive variable arguments"
[data group-keys aggregates]
(->> data
(group-by (fn [item] (select-keys item group-keys)))
(map (fn [[_group-key items]]
(merge (select-keys (first items) group-keys)
(into {}
(map (fn [[aggregate-fn aggregate-key rename]]
(vector (or rename aggregate-key)
(apply aggregate-fn
(->> (map aggregate-key items)
(remove nil?)))))
aggregates)))))))
;; usage
(def inventory-txs
[{:id "tx1"
:pid "p1"
:desc "Inventory input Product P1"
:amount 10
:created 1673308800000}
{:id "tx2"
:pid "p1"
:desc "Inventory output Product P1"
:amount -5
:created 1674172800000}
{:id "tx3"
:pid "p2"
:desc "Invoice input Product P2"
:amount 8
:created 1673395200000}])
(aggregate-data inventory-txs [:pid]
[[+ :amount]
[max :created :latest-tx-date]])
;; result
({:pid "p1", :amount 5, :latest-tx-date 1674172800000}
{:pid "p2", :amount 8, :latest-tx-date 1673395200000})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment