Vector Clojure;如何迭代映射向量,以便索引已知,以便能够在映射中更新?
假设我把这个原子作为游戏的状态:Vector Clojure;如何迭代映射向量,以便索引已知,以便能够在映射中更新?,vector,clojure,hashmap,Vector,Clojure,Hashmap,假设我把这个原子作为游戏的状态: (defonce state (atom {:player {:cells [{:x 123 :y 456 :radius: 1.7 :area 10} {:x 456 :y 789 :radius: 1.7 :area 10} {...}]}})) 我想读取其中一个单元格的位置,(在:c
(defonce state (atom {:player
{:cells [{:x 123 :y 456 :radius: 1.7 :area 10}
{:x 456 :y 789 :radius: 1.7 :area 10}
{...}]}}))
我想读取其中一个单元格的位置,(在:cells向量中的映射:x和:y值)用这些值计算它们在下一帧中应该位于的位置,然后在计算时更新相应映射中新的:x和:y位置
到目前为止,我有:
(let [cells (get-in @state [:player :cells])]
(reduce
(fn
[seq cell]
(let [cell-x (get-in cell [:x])
cell-y (get-in cell [:y])]
; do my calculations
; ...
))
nil
cells))
所以我可以读取值并进行计算,但是我如何用新值更新x和y位置?我可以使用:
(swap! state update-in [:player :cells ...] assoc :x new-x :y new-y)
但是在那里我不知道索引。。。在哪个向量中更新它
我假设有一种不使用reduce的方法可以得到索引
或者我正在接近完全不惯用的方式?您可以更新特定的哈希映射对象,而不知道向量中的索引:
(let [when-x 123
new-x -1
new-y -1]
(swap! state update-in [:player :cells]
(fn [v] (mapv (fn [{:keys [x y] :as m}]
(if (= x when-x)
(assoc m :x new-x :y new-y)
m))
v))))
;;=> {:player {:cells [{:x -1, :y -1, :radius 1.7, :area 10}
;; {:x 456, :y 789, :radius 1.7, :area 10}]}}
当您有一些可能需要更新许多值的标准时,此代码非常有用。注意,在这里我们不需要知道索引就可以进行更新
现在进行一次轻微的偏移,但是如果您只需要更新一个特定的已知索引,那么一种方法就是使用相同的技术,但是使用地图索引
,而不是mapv
:
(let [when-idx 1
new-x -1
new-y -1]
(swap! state update-in [:player :cells]
(fn [v] (vec (map-indexed (fn [n {:keys [x y] :as m}]
(if (= n when-idx)
(assoc m :x new-x :y new-y)
m))
v)))))
但是,这对于您的数据来说毫无意义,因为向量是一个关联集合,因此updatein
将能够按索引选择:
(let [when-idx 0
new-x -1
new-y -1]
(swap! state update-in [:player :cells when-idx] #(assoc % :x new-x :y new-y)))
有趣的是,如果不是向量而是一个列表,那么它并不是毫无意义的,({:x123:y456:radius 1.7:area 10}{:x456:y789:radius 1.7:area 10})
。对于此非关联集合,您不能在中使用更新
这种构造并非毫无意义的另一个原因是,如果您担心性能:您可以利用惰性来缩短寻找答案的时间:
(defn replace-in [v [idx new-val]]
(concat (subvec v 0 idx)
[new-val]
(subvec v (inc idx))))
(let [when-x 123
new-x -1
new-y -1]
(swap! state update-in [:player :cells]
(fn [v] (->> v
(keep-indexed (fn [idx {:keys [x] :as m}]
(when (= x when-x)
[idx (assoc m :x new-x :y new-y)])))
first
(replace-in v)))))
keep indexed
与map indexed
类似,只是任何nil
值都不会返回到输出序列中。一旦实现了第一个
值,则不会产生剩余的电位值,因此短路。这里,idx
用于调用subvec
来切碎原始向量并包含新的哈希映射对象。您是否检查了specter?它对这类东西有很好的支持:谢谢你提供了这些选择!换句话说,没有clojure核心函数,它允许我通过给我迭代的索引来“迭代”向量?是的。您所描述的正是映射索引的功能。