In Clojure, I would like to combine several maps into a single map where mappings with same key are combined into a list.
For example:
{:humor :happy} {:humor :sad} {:humor :happy} {:weather :sunny}
should lead to:
{:weather :sunny, :humor (:happy :sad :happy)}
I thought about:
(merge-with (comp flatten list) data)
But it is not efficient because flatten has O(n) complexity.
Then I came up with:
(defn agg[x y] (if (coll? x) (cons y x) (list y x)))
(merge-with agg data)
But it feels not idiomatic. Any other idea?
One approach would be
It’s a bit ugly, but that’s only because your values aren’t already lists. It also forces everything to be a list (so you’d get
:weather [:sunny]rather than:weather :sunny). Frankly, this is likely to be a million times easier for you to work with anyway.If you had each value as a vector already, you could simply do
(apply merge-with into maps). So, another thing you could try would be to convert to vectors first, and then do the simplemerge-with. This probably performs a bit worse than the first approach because of the intermediate data structures.