Вкратце, как применить функцию к выбранным элементам в [большом] векторе - PullRequest
8 голосов
/ 20 ноября 2011

У меня есть вектор v

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

Я хочу применить функцию myfn

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

к выбранным элементам, индексы которых у меня есть idx

(def idx [3 5])

Я видел Как изменить часть вектора в Clojure? и это не совсем то, что мне нужно.

Как то, что вы делаете в MATLAB

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

Ответы [ 4 ]

9 голосов
/ 20 ноября 2011

Векторы в clojure являются ассоциативными, поэтому вы можете сделать что-то вроде этого: (reduce #(update-in %1 [%2] myfn) v idx)

3 голосов
/ 20 ноября 2011

Обновлено, поскольку я неверно истолковал вопрос.

Вот еще одно решение:

(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 голосов
/ 20 ноября 2011

Вы упомянули «большой вектор», так что вы заботитесь о производительности?Вы можете узнать о переходных процессах :

(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)))
0 голосов
/ 20 ноября 2011
(let [sidx (set idx)]
  (vec                        ;(sidx i)
    (map-indexed (fn [i x] (if (contains? sidx i) (myfn x) x)) v)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...