2
votes

assoc-in can change a value at an index/key in vectors/maps. In maps, if an key does not exist, then it makes a new key/value pair. Is there something similiar for vectors (if an index does not exist, it makes a list with that value at that index) Something like:

 (reduce (fn [g [x y]] (assoc-in g [x y] y ))
        []
        (for [x (range 2) 
              y (range 2)]
             [x y]))

above code generates:

[{1 1, 0 0} {1 1, 0 0}]

I want it to generate:

[[0 1] [0 1]]

Is this possible in a simple way?

Thanks

EDIT: To be more clear, I Just want it to generate nested vectors instead of nested maps (or a vector of maps) Now I put y as a value but that's just an example.

2
Can you clarify what [[0 1] [0 1]] means? Is it a vector of two vectors created from (range 2)? or something else?Alexey Kachayev
Sure, sorry to be unclear. I Just want it to generate nested vectors instead of nested maps (or vector of maps) I'll edit my questionuser1782011

2 Answers

6
votes

Creating a vector rather than a map won't work well in the general case because you can only assoc an existing index or the next index in a vector:

user=> (assoc [:a] 0 :b) ; works because index 0 exists
[:b]
user=> (assoc [:a] 1 :b) ; works because index 1 is next
[:a :b]
user=> (assoc [:a] 2 :b) ; fails since index is out of range
IndexOutOfBoundsException   clojure.lang.PersistentVector.assocN (PersistentVector.java:136)

However, if you're careful you can still make it work. Here is the implementation for assoc-in:

(defn assoc-in
  [m [k & ks] v]
  (if ks
    (assoc m k (assoc-in (get m k) ks v))
    (assoc m k v)))

Notice that it calls get on the true branch of the if condition. If you want your own version of assoc-in that uses vectors instead, you can add an empty vector as the default value returned by get:

(defn vassoc-in
  [m [k & ks] v]
  (if ks
    (assoc m k (vassoc-in (get m k []) ks v))
    (assoc m k v)))

Using vassoc-in rather than assoc-in in the sample code in your question results in [[0 1] [0 1]] just like you wanted.

0
votes

It seems that you need something like:

user=> (let [cv #(apply vector %)] 
         (cv (map cv (repeat 5 (range 2)))))
[[0 1] [0 1] [0 1] [0 1] [0 1]]