Map Clojure嵌套映射路径

Map Clojure嵌套映射路径,map,clojure,tree,hierarchical-data,Map,Clojure,Tree,Hierarchical Data,这确实是问题的后续 我需要能够改变一个包含子贴图列表的贴图的原子。我想在中使用fx assoc来执行此操作,但我不确定如何最好地选择要更改的元素的路径 我的数据结构: (def x (atom {:name "A" :id 1 :children [{:name "B" :id 2 :children []} {:na

这确实是问题的后续

我需要能够改变一个包含子贴图列表的贴图的原子。我想在中使用fx assoc来执行此操作,但我不确定如何最好地选择要更改的元素的路径

我的数据结构:

(def x (atom {:name "A" 
          :id 1 
          :children [{:name "B" 
                      :id 2 
                      :children []} 
                     {:name "C" 
                      :id 3 
                      :children [{:name "D" 
                                  :id 4 
                                  :children []}]}]}))
如何创建函数来查找给定id的路径,fx give me path to map包含#(=(:id%)3):

因此,我可以这样做以获得新地图:

(assoc-in @x [(conj (find-path...) :name)] "Jim")
或者像这样更新Atom:

(swap! x assoc-in [(conj (find-path...) :name)] "Bob")
使用创建一个拉链,然后使用迭代遍历每个位置,一旦找到了包含节点的位置(id为
id
),开始沿途移动构建路径

(defn path-from-root
  [loc]
  (loop [path []
         loc loc]
    (if-let [parent (zip/up loc)]
      (recur (into [:children (-> loc zip/lefts count)] path)
             parent)
      path)))
下面是我用来完成最后一步的一个函数,它向上移动到根目录并沿途构建路径

(defn path-from-root
  [loc]
  (loop [path []
         loc loc]
    (if-let [parent (zip/up loc)]
      (recur (into [:children (-> loc zip/lefts count)] path)
             parent)
      path)))
使用创建一个拉链,然后使用迭代遍历每个位置,一旦找到了包含节点的位置(id为
id
),开始沿途移动构建路径

(defn path-from-root
  [loc]
  (loop [path []
         loc loc]
    (if-let [parent (zip/up loc)]
      (recur (into [:children (-> loc zip/lefts count)] path)
             parent)
      path)))
下面是我用来完成最后一步的一个函数,它向上移动到根目录并沿途构建路径

(defn path-from-root
  [loc]
  (loop [path []
         loc loc]
    (if-let [parent (zip/up loc)]
      (recur (into [:children (-> loc zip/lefts count)] path)
             parent)
      path)))

这里的一个基本问题是,您的更新过程现在是一个两步过程:
查找路径
更新路径
。但是,您正在使用原子,因此当
update in
查看原子值时,
find path
返回的路径可能不正确

因此,您应该将它们组合在一个fn中,这样就不会有一个
deref
和一个
交换

(defn update-by-id [x id f & args]
  (apply update-in x (find-path x id) f args))
现在您可以使用单个
交换

(swap! x update-by-id 3 assoc :name "Bob")

但是,如果您经常通过ids进行更新和访问,您还应该评估切换到此数据段的另一种(更平坦的)表示形式。

这里有一个基本问题,即您的更新过程现在是一个两步过程:
查找路径
中更新。但是,您正在使用原子,因此当
update in
查看原子值时,
find path
返回的路径可能不正确

因此,您应该将它们组合在一个fn中,这样就不会有一个
deref
和一个
交换

(defn update-by-id [x id f & args]
  (apply update-in x (find-path x id) f args))
现在您可以使用单个
交换

(swap! x update-by-id 3 assoc :name "Bob")

但是,如果您经常通过ids进行更新和访问,您还应该评估切换到此数据段的另一种(更平坦的)表示形式。

您可以使用来自的拉链。我认为创建返回路径的递归函数应该很容易,但我无法让它工作。在我看来,使用zipper来推理和操作持久嵌套结构要比试图找到一个递归函数来处理它们容易得多。你可以使用zipper from。我认为让递归函数返回路径应该很容易,但我不能让它工作。在我看来,使用Zipper来推理和操作持久性嵌套结构要比试图找出一个递归函数来处理它们容易得多。这一点很好。数据经常被读取,很少被更新,但这两种操作都可能会因为深层结构而代价高昂。这一点很好。数据经常被读取,很少被更新,但这两种操作都可能因为深层结构而代价高昂。