Hi huys : I want to map a "average" for all values in a map. say I have a list of maps :
[{"age" 2 "height" 1 "weight" 10},
{"age" 4 "height" 4 "weight" 20},
{"age" 7 "height" 11 "weight" 40}]
And my desired output is
{"age 5 "height" 5 ....}
///Below are the ramblings of my brain, i.e. the way I might imagine this working in Clojure...not to be taken too seriously
transpose the list :
{"age" [2 4 7] "height" [1 4 11] }
and then I could simply do something like (again, making up a function called freduce here)
(freduce average (vals (map key-join list)))
to get
{"age" 5 "weight" 10 "height" 7}
Create the map of vectors:
(reduce (fn [m [k v]] (assoc m k (conj (get m k []) v))) {} (apply concat list-of-maps))
Create the map of averages:
(reduce (fn [m [k v]] (assoc m k (/ (reduce + v) (count v)))) {} map-of-vectors)
Take a look at merge-with
Here's my go at some actual code:
(let [maps [{"age" 2 "height" 1 "weight" 10},
{"age" 4 "height" 4 "weight" 20},
{"age" 7 "height" 11 "weight" 40}]]
(->> (apply merge-with #(conj %1 %2)
(zipmap (apply clojure.set/union (map keys maps))
(repeat [])) ; set the accumulator
maps)
(map (fn [[k v]] [k (/ (reduce + v) (count v))]))
(into {})))
Here's a fairly verbose solution. Hopefully someone can come up with something better:
(let [maps [{"age" 2 "height" 1 "weight" 10},
{"age" 4 "height" 4 "weight" 20},
{"age" 7 "height" 11 "weight" 40}]
ks (keys (first maps))
series-size (count maps)
avgs (for [k ks]
(/ (reduce +
(for [m maps]
(get m k)))
series-size))]
(zipmap ks avgs))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With