无法通过逐个元素循环来更新向量

时间:2011-07-06 10:01:48

标签: loops vector clojure

我试图通过循环设置向量的每个元素等于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 个答案:

答案 0 :(得分:9)

您的更新功能无法按预期工作。

(assoc w index value)

基于w生成 new 向量,但 index 处的元素现在是 value 。它不会改变

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

此外,您没有正确使用循环/重复。你开始循环,我绑定到-1,打算用它作为w的索引,但是recur调用循环不是用i的下一个值,而是用更新返回的w的更改副本。

尝试更多类似的内容:

(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))

Map返回一个序列,我将它包装在对 vec 的调用中,将其转换回矢量。

答案 1 :(得分:3)

通过将(update ...)传递给recur函数来混合整数和向量类型。循环语句应该看起来像(loop [i -1 w w] ..)然后你可以将你的新向量收集到本地“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 :(得分:2)

您可以使用地图并不断地执行此操作:

(def w [1 2 3])

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

请注意,这不会改变w - 它返回一个与w长度相同的新三个序列。因此,使用以下方法可以获得相同的结果:

(repeat (count w) 3)
=> 3

如果实际上想要更改w,那么我建议将w转换为原子,以便可以使用交换进行更新!功能:

(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中看起来相当单一和必要,但确实有效......