Reputation: 59
Given a vector:
(def vec [{:key 1, :value 10, :other "bla"}, {:key 2, :value 13, :other "bla"}, {:key 1, :value 7, :other "bla"}])
I'd like to iterate over each element and update :value
with the sum of all :value
s to that point, so I would have:
[{:key 1, :value 10, :other "bla"}, {:key 2, :value 23, :other "bla"}, {:key 1, :value 30, :other "bla"}])
I've found this for printing the result, but I've tried to change the prn
command to update-in
, assoc-in
in the code below (extracted from the link above) but I didn't work quite well.
(reduce (fn [total {:keys [key value]}]
(let [total (+ total value)]
(prn key total)
total))
0 vec)
I'm new to Clojure, how can I make it work?
Upvotes: 1
Views: 205
Reputation: 13473
You can accumulate the :value
s thus:
(reductions + (map :value v))
=> (10 23 30)
(I renamed the vector v
to avoid tripping over clojure.core/vec
.)
Then you can use mapv
over assoc
:
(let [value-sums (reductions + (map :value v))]
(mapv #(assoc %1 :value %2) v value-sums))
=> [{:key 1, :value 10, :other "bla"} {:key 2, :value 23, :other "bla"} {:key 1, :value 30, :other "bla"}]
Upvotes: 1
Reputation: 6509
If you want to get the running totals then the simplest way is to use reductions
:
(reductions (fn [acc ele] (+ acc (:value ele)))
0
[{:key 1, :value 10, :other "bla"}, {:key 2, :value 13, :other "bla"}, {:key 1, :value 7, :other "bla"}])
;; => (0 10 23 30)
As you can see the function you pass to reductions
has the same signature as the function you pass to a reduce
. It is like you are asking for a reduce
to be done every time a new element is reached. Another way of thinking about it is that every time a new accumulator is calculated it is kept, unlike with reduce
where the caller only gets to see the result of the last calculation.
And so this is the code that would directly answer your question:
(->> [{:key 1, :value 10, :other "bla"}, {:key 2, :value 13, :other "bla"}, {:key 1, :value 7, :other "bla"}]
(reductions #(update %2 :value + (:value %1))
{:value 0})
next
vec)
;; => [{:key 1, :value 10, :other "bla"} {:key 2, :value 23, :other "bla"} {:key 1, :value 30, :other "bla"}]
Upvotes: 2