I have a vector v
(def v [1 2 5 8 4 3 8 9 3])
I want to apply function myfn
(defn myfn [x] (+ 1 x))
to selected items that I have their indexes idx
(def idx [3 5])
I've seen How do I modify a portion of a vector in Clojure? and it is not exactly what I need.
Like what you do in MATLAB
v = [1 2 5 8 9 3];
idx = [3 5];
v(idx) = myfn(v(idx));
Vectors in clojure are associative, so you can do something like this: (reduce #(update-in %1 [%2] myfn) v idx)
Updated because I misinterpreted the question.
Here's another solution:
(apply assoc v (mapcat #(vector % (myfn (v %))) idx))
that is, build up an argument list of index/new-value pairs to assoc
. I think mange's solutions is probably better though.
Original, incorrect solution
Don't forget that vector v
is itself a function of its indices. So:
(map myfn (map v idx))
or:
(->> idx (map v) (map myfn))
or:
(map (comp myfn v) idx)
I'm sure there's also a very clever answer involving juxt
:)
You mention "a [large] vector", so do you care about performance? You may want to find out about transients:
(persistent!
(reduce (fn [v i] (assoc! v i (myfn (get v i))))
(transient v)
idx))
Or, if you prefer looping style, this does the same thing:
(loop [v (transient v), [i & is :as idx] idx]
(if (empty? idx)
(persistent! v)
(recur (assoc! v i (myfn (get v i))) is)))
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