TL;DR
update-vals
and update-keys
are mainly supposed to operate on maps of homogenous data that are keyed on some identifier.
https://clojure.atlassian.net/browse/CLJ-2651
https://clojure.atlassian.net/browse/CLJ-1959
But there is no function in core that produces such a map from a sequence of homogenous data. I guess there are a lot of ways to achieve this, for example
(into {} (map (juxt f identity)) coll) ; credit Sean Corfield
(persistent! (reduce #(assoc! %1 (f %2) %2) (transient {}) coll)) ; from Medley
(update-vals first (group-by f coll))
But I have no idea which is most performant. So, I wonder if there is a place for a key-by
function in core that produces such a map with good performance?
Clojure 1.11 introduced update-keys
and update-vals
, and I (and I presume others) started using them instead of our handwritten map-vals
and the likes.
However, I am still uncertain on the best way to create a map that update-keys
and update-vals
operate on. Typically, I will have a sequence of homogenous maps retrieved from a database, like
[{:id 1 :name "brandon"}
{:id 2 :name "brenda"}
{:id 3 :name "kelly"}]
and a (key-by :id coll)
or (index-by :id coll)
function turns it into
{1 {:id 1 :name "brandon"}
2 {:id 2 :name "brenda"}
3 {:id 3 :name "kelly"}}
But how is this best achieved? update-vals
allows for
(defn key-by
[f coll]
(update-vals first (group-by f coll)))
But these collections are often large and one wants good perfomance. In Medley, index-by
is written as such
(defn index-by
[f coll]
(persistent! (reduce #(assoc! %1 (f %2) %2) (transient {}) coll)))
Which looks faster and is something that I could never have come up with. So I can't help but wonder if key-by
(that name sounds better to me) became a missing piece in Clojure core when update-keys
and update-vals
were introduced?