Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Idiomatic way to assoc multiple elements in vector

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.

like image 306
user3399829 Avatar asked Mar 29 '14 11:03

user3399829


1 Answers

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)))
like image 193
xsc Avatar answered Sep 28 '22 15:09

xsc