Question

I have a one-dimensional vector, a vector of indices to update within the vector, and a value which should be associated with each of these indices.

I'm new to Clojure, and imagine that there might be a more idiomatic way to write the routine that I ended up with:

(defn update-indices-with-value [v indices value]
  (loop [my-v v 
         my-indices indices
         my-value value]
    (if (empty? my-indices)
      my-v
      (recur (assoc my-v (peek my-indices) my-value)
             (pop my-indices)
             my-value)))) 

I know that assoc can be used to update multiple keys or indices within an associative collection, but I couldn't figure out the syntactic magic to use assoc with an arbitrary list of keys or indices.

Was it helpful?

Solution

Use reduce:

(defn assoc-all
  [v ks value]
  (reduce #(assoc %1 %2 value) v ks))

Example:

(assoc-all [1 2 3 4] [0 1] 2)
;; => [2 2 3 4]

Alternatively, create the key/value pairs and use apply:

(defn assoc-all
  [v ks value]
  (->> (interleave ks (repeat value))
       (apply assoc v)))

If assoc was using transients internally this might actually be more efficient than the reduce version. Since it isn't, the lazy sequence overhead is probably eating it all up.

So, finally, a transient version:

(defn assoc-all
  [v ks value]
  (persistent!
    (reduce
      #(assoc! %1 %2 value)
      (transient v)
      ks)))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top