In this case the usual recommendation is to do the group-by
first and then your processing after.
(let [data [{:class :a, :numbers [10], :count? true}
{:class :b :numbers [3], :count? true}
{:class :a, :numbers [88], :count? true}]]
(m/find (group-by :class data)
{?class [(m/or {:numbers [!nums ...] :count? true} _) ...] & (m/cata ?rest)}
(cons {:class ?class :numbers (reduce + !nums) :count? true} ?rest)
{}
()))
;; =>
({:class :a, :numbers 98, :count? true}
{:class :b, :numbers 3, :count? true})
Aggregation is something that comes up a lot and we will have something specifically for it available by summer (along with other things).
Thanks for the tip!
I spent some time tracking down a bug last week that turned out to be due to my use of the (and !memvar1 !memvar2)
method from the cookbook for re-using a memvar in two different places in the output pattern, coupled with the ..!n
syntax
something like [(m/and !m1 !m2) ..!n]
-> {:a [!m1 ..!n] :b [!m2 ..!n]}
, except nested in a much more complicated pattern
The bug was pretty obvious once discovered but it occured to me that such constructs can be pretty hard to reason about in subtle ways.. with an imperative flavour of pushing and popping from arrays and keeping track of indices
The next logical step is asking whether there exists some sort of ..(and !n1 !n2)
syntax , but that just seems like a further step in the wrong direction..
really the [[!x ..!n] ...]
syntax is a way of fitting multidimensional data into a linear memory variable, I wonder if there could be a less clunky way of encoding this
With fold and unfold we will have more power to implement better ways of doing these things. But my recommendation is also to dream up your ideal way and share it. Maybe it will be implemented or maybe it will spark other with more ideas.
Ideas are absolutely welcome.
Question about variable number of forms:
;; This works:
(def data
'((path "/a"
(PUT "Updates A"))
(path "/b"
(GET "Gets a B"))))
(m/rewrite
data
((path !path (!method !desc)) ..!paths)
[{:path !path
:routes
{:method !method
:desc !desc}} ..!paths])
;; But this was harder, when adding more routes to a path:
(def data
'((path "/a"
(PUT "Updates A"))
(path "/b"
(PUT "Gets a B")
(PUT "Updates B"))))
;; Desired output
[{:path "/a" :routes [{:method 'PUT :desc "Updates A"}]}
{:path "/b" :routes [{:method 'GET :desc "Gets a B"}
{:method 'PUT :desc "Updates B"}]}]
I’ve tried to make it seqable and some other things, but can’t find the way to make this work. What am I missing?(let [data
'((path "/a"
(PUT "Updates A"))
(path "/b"
(PUT "Gets a B")
(PUT "Updates B")))]
(m/rewrite
data
((path !path . (!method !desc) ..!routes) ..!paths)
[{:path !path
:routes [{:method !method
:desc !desc} ..!routes]} ..!paths]))
;; =>
[{:path "/a",
:routes [{:method PUT, :desc "Updates A"}]}
{:path "/b",
:routes [{:method PUT, :desc "Gets a B"}
{:method PUT, :desc "Updates B"}]}]
Keep in mind you can always use cata
to do nested transforms with separate rules rather than all in one shot.
Ah… I was more or less in dot from finding the solution then! Close, but no cigar! 🙂 Thank you very much, @noprompt!