开发者

Cannot update vector by looping element by element

开发者 https://www.devze.com 2023-03-17 20:48 出处:网络
I am trying to set each element of a vector equal to 3 by looping. I get: java.lang.ClassCastException: clojure.lang.PersistentVector can

I am trying to set each element of a vector equal to 3 by looping. I get:

java.lang.ClassCastException: clojure.lang.PersistentVector can not be cast to java.lang.Number

This is the code.

(def w [1 2 3])
(defn update [index value]
  (assoc开发者_如何学Python w index value))

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


Your update function doesn't work the way you expect.

(assoc w index value)

Produces a new vector based on w, except that the element at index is now value. It doesn't change w.

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

Also, you're not using loop/recur correctly. You begin the loop with i bound to -1, intending to use it as an index into w, but recur calls the loop not with the next value of i, but rather with an altered copy of w as returned by update.

Try something more like:

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

But, since you're not actually using the index to compute the new value of the element, you can use map instead of loop. Since just setting each element to a constant value without considering its old value, you can use clojure's built-in function constantly.

(vec (map (constantly 3) w))

Map returns a sequence, I've wrapped it in a call to vec to transform it back into a vector.


You are mixing integer and vector type by passing (update ...) to recur function. The loop statement should be look like (loop [i -1 w w] ..) and then you could collect your new vector into the local "w". If you want to use recure statement this code can help you (I guess there are a lot of other options to change values of a vector):

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

  (loop [i  0
         w  w]
    (if (< i (count w))
      (recur (inc i) (assoc w i value))
      w)))


You can do this with map and constantly:

(def w [1 2 3])

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

Note that this doesn't change w - it returns a new sequence of threes that is the same length as w. Therefore you could equally get the same result by using:

(repeat (count w) 3)
=> 3

If you actually want to change w, then I would suggest making w into an atom so it can be updated with a swap! function:

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

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

@w
=> [3 3 3]

Finally, if you really want to update the elements of w one at a time, you can do something like:

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

This seems rather unidiomatic and imperative in Clojure, but it does work.....

0

精彩评论

暂无评论...
验证码 换一张
取 消