2017-08-08 40 views
1

假设我有这个原子作为游戏的状态:Clojure;如何迭代地图矢量,以便索引已知,以便能够更新地图?

(defonce state (atom {:player 
         {:cells [{:x 123 :y 456 :radius: 1.7 :area 10} 
           {:x 456 :y 789 :radius: 1.7 :area 10} 
           {...}]}})) 

,我想读取其中细胞中的一个,(在地图: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) 

但我不知道该指数...在向量来更新它

我假设有没有用减少的方式,会给我的索引。 ?

还是我接近这完全没有惯用?

+0

你检查了幽灵吗?它有很好的支持,有点东西:https://github.com/nathanmarz/specter –

回答

1

你可以不知道该指数在矢量更新特定哈希映射对象:在这里你有一定的标准对其中潜在的许多值需要更新

(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}]}} 

此代码是非常有用的。请注意,在这里我们不需要知道索引来进行更新。现在

去有轻微的偏移,但如果你需要更新只有一个特定的已知指数,其中一个方法是使用相同的技术,但与map-indexed代替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))))) 

但是那会是毫无意义的与您的数据,因为向量是一个关联集,因此update-in将能够通过指数来选择:

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

有趣的注意,它不会不过是毫无意义如果不是一个载体,你有一个列表,所以'({:x 123 :y 456 :radius 1.7 :area 10}{:x 456 :y 789 :radius 1.7 :area 10})。有了这个非关联集合,你不能使用update-in

这种结构不会是毫无意义的另一个原因是,如果你是担心的表现:你可以用懒惰短路找到了答案:

(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用来截取原始向量并包含新的哈希映射对象。

+0

谢谢你的替代品! 换句话说,没有clojure核心函数,它允许我通过给迭代的索引“遍历”一个向量? – Andimanos

+0

是的。你所描述的正是'map-indexed'所做的。 –

相关问题