Невозможно обновить вектор путем зацикливания элемента на элемент - PullRequest
3 голосов
/ 06 июля 2011

Я пытаюсь установить каждый элемент вектора равным 3 с помощью цикла.Я получаю:

java.lang.ClassCastException: clojure.lang.PersistentVector не может быть приведен к java.lang.Number

Это код.

(def w [1 2 3])
(defn update [index value]
  (assoc w index value))

(loop [i -1]
  (if (< (count w) i)
    w
    (recur (update (+ i 1) 3))))

Ответы [ 3 ]

9 голосов
/ 06 июля 2011

Ваша функция обновления работает не так, как вы ожидаете.

(assoc w index value)

Создает новый вектор на основе w, за исключением того, что элемент в index теперь значение . не меняется w .

user> (def w [1 2 3])
user> (assoc w 0 9)
    [9 2 3]
user> w
    [1 2 3]

Кроме того, вы не используете цикл / рекурсивно.Вы начинаете цикл с i, привязанного к -1, намереваясь использовать его в качестве индекса для w, но recur вызывает цикл не со следующим значением i, а с измененной копией w, возвращаемой update.

Попробуйте что-то вроде:

(def w [1 2 3])
(loop [i 0, v w]
    (if (< (count w) i)
        v
        (recur (inc i) (assoc v i 3))))

Но, поскольку вы фактически не используете индекс для вычисления нового значения элемента, вы можете использовать map вместо цикла,Поскольку просто устанавливая для каждого элемента постоянное значение без учета его старого значения, вы можете использовать встроенную функцию clojure постоянно .

(vec (map (constantly 3) w))

Карта возвращает последовательность, я обернул еев вызове vec , чтобы преобразовать его обратно в вектор.

3 голосов
/ 06 июля 2011

Вы смешиваете целочисленный и векторный тип путем передачи (update ...) в функцию recur.Оператор цикла должен выглядеть следующим образом (loop [i -1 ww] ..), и тогда вы можете собрать свой новый вектор в локальную букву "w".Если вы хотите использовать выражение recure, этот код может помочь вам (я думаю, что есть много других вариантов изменения значений вектора):

(let [value 4
      w [1 2 3]]

  (loop [i  0
         w  w]
    (if (< i (count w))
      (recur (inc i) (assoc w i value))
      w)))
2 голосов
/ 06 июля 2011

Вы можете делать это с картой и постоянно:

(def w [1 2 3])

(map (constantly 3) w)
=> (3 3 3)

Обратите внимание, что это не меняет w - оно возвращает новую последовательность троек, которая имеет ту же длину, что и w.Следовательно, вы можете получить тот же результат, используя:

(repeat (count w) 3)
=> 3

Если вы на самом деле хотите изменить w, то я бы предложил превратить w в атом, чтобы его можно было обновить с помощьюсвоп!function:

(def w (atom [1 2 3]))

(swap! w 
  (fn [old-w]
    (vec (map (constantly 3) old-w))))

@w
=> [3 3 3]

Наконец, если вы действительно хотите обновлять элементы w по одному, вы можете сделать что-то вроде:

(dotimes [i (count @w)]
  (swap! w 
    (fn [previous-w]
      (assoc previous-w i 3))))

Это кажется довольно однотипным и обязательным вClojure, но это работает .....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...