Clojure; 如何遍历地图向量,以便知道索引,以便能够在地图中更新?

安迪马诺斯

假设我有这个原子作为游戏的状态:

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

当您有一些可能需要更新许多值的标准时,此代码很有用。请注意,这里我们不需要知道索引来进行更新。

现在稍微进行一下游览,但是如果您只需要更新一个特定的已知索引,那么一种方法是使用相同的技术,但使用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值返回到输出序列中。一旦该first值被实现,其余的潜在值就永远不会产生,因此短路。Hereidx被调用用于subvec切碎原始向量并包含新的哈希映射对象。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

更新Clojure中的地图向量中的值

来自分类Dev

Clojure:如何更新地图中的多个值

来自分类Dev

从Clojure中的向量构造地图

来自分类Dev

Clojure:地图地图

来自分类Dev

在Clojure中,如何正确更新嵌套地图?

来自分类Dev

按地图中的值对地图中的向量对这些向量进行排序-Clojure

来自分类Dev

Clojure-地图值

来自分类Dev

合并Clojure中的地图

来自分类Dev

Clojure嵌套地图路径

来自分类Dev

合并Clojure中的地图

来自分类Dev

Clojure地图数组

来自分类Dev

排序嵌套地图Clojure

来自分类Dev

Clojure - 创建嵌套地图

来自分类Dev

在 Clojure 中迭代地图

来自分类Dev

Clojure方法来更新向量中的地图

来自分类Dev

Clojure在地图和向量之间决定

来自分类Dev

在 Clojure 中从地图构建嵌套向量

来自分类Dev

Clojure:地图中的汇总和计数

来自分类Dev

clojure:使用多个键在地图中搜索

来自分类Dev

Clojure,计算地图中的单词数

来自分类Dev

使用Clojure从地图中删除键

来自分类Dev

Clojure:如何合并具有相同值的地图向量

来自分类Dev

在Clojure中,如何合并两个地图向量?

来自分类Dev

如何在Clojure的嵌套地图中选择键?

来自分类Dev

Clojure:对地图向量中的地图中的每个值应用函数

来自分类Dev

Clojure:将函数应用于地图向量中的地图中的每个值

来自分类Dev

在Clojure中转换地图键

来自分类Dev

Clojure-地图功能

来自分类Dev

是否在Clojure中订购地图?