在clojure中,如何将函数应用于[大]向量中的选定项

时间:2011-11-20 02:24:00

标签: matlab clojure

我有一个向量v

(def v [1 2 5 8 4 3 8 9 3])

我想应用函数myfn

(defn myfn [x] (+ 1 x))

选择我的索引为idx

的项目
(def idx [3 5])

我见过How do I modify a portion of a vector in Clojure?,这并不是我所需要的。

就像你在MATLAB中做的那样

v = [1 2 5 8 9 3];
idx = [3 5];
v(idx) = myfn(v(idx));

4 个答案:

答案 0 :(得分:9)

clojure中的向量是关联的,因此您可以执行以下操作:(reduce #(update-in %1 [%2] myfn) v idx)

答案 1 :(得分:3)

更新,因为我误解了这个问题。

这是另一种解决方案:

(apply assoc v (mapcat #(vector % (myfn (v %))) idx))

即,为assoc建立索引/新值对的参数列表。我认为mange的解决方案可能更好。


原创,错误的解决方案

不要忘记向量v本身就是其索引的函数。所以:

(map myfn (map v idx))

或:

(->> idx (map v) (map myfn))

或:

(map (comp myfn v) idx)

我确信还有一个非常聪明的答案涉及juxt:)

答案 2 :(得分:2)

你提到“一个[大]矢量”,所以你关心性能吗?您可能想了解transients

(persistent!
  (reduce (fn [v i] (assoc! v i (myfn (get v i))))
          (transient v)
          idx))

或者,如果您更喜欢循环风格,这也会做同样的事情:

(loop [v (transient v), [i & is :as idx] idx]
  (if (empty? idx)
    (persistent! v)
    (recur (assoc! v i (myfn (get v i))) is)))

答案 3 :(得分:0)

(let [sidx (set idx)]
  (vec                        ;(sidx i)
    (map-indexed (fn [i x] (if (contains? sidx i) (myfn x) x)) v)))