关于Clojure:Assoc-in可以创建新的向量而不是新的地图吗?

Can assoc-in create a new vector instead of a new map?

assoc-in可以更改矢量/地图中索引/键处的值。 在地图中,如果不存在键,则它将创建一个新的键/值对。 向量有什么类似的东西吗(如果不存在索引,它将创建一个在该索引处具有该值的列表),例如:

1
2
3
4
5
 (reduce (fn [g [x y]] (assoc-in g [x y] y ))
        []
        (for [x (range 2)
              y (range 2)]
             [x y]))

上面的代码生成:

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

我希望它生成:

1
[[0 1] [0 1]]

这有可能简单吗?

谢谢

编辑:
更清楚地说,我只希望它生成嵌套向量而不是嵌套地图(或地图向量)。现在我将y用作值,但这仅是示例。


在一般情况下,创建矢量而不是地图将无法正常工作,因为您只能assoc现有索引或矢量中的下一个索引:

1
2
3
4
5
6
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)

但是,如果您小心一点,仍然可以使它起作用。 这是assoc-in的实现:

1
2
3
4
5
(defn assoc-in
  [m [k & ks] v]
  (if ks
    (assoc m k (assoc-in (get m k) ks v))
    (assoc m k v)))

注意,它在if条件的真实分支上调用get。 如果您想要自己的使用向量的assoc-in版本,则可以添加一个空向量作为get返回的默认值:

1
2
3
4
5
(defn vassoc-in
  [m [k & ks] v]
  (if ks
    (assoc m k (vassoc-in (get m k []) ks v))
    (assoc m k v)))

在您的问题的示例代码中使用vassoc-in而不是assoc-in会像您想要的那样生成[[0 1] [0 1]]


似乎您需要以下内容:

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