How to move an element within a structure, possibly with zippers?

假装没事ソ 提交于 2019-12-24 03:59:05

问题


I have this structure:

 [{"a" {"b" 1 "c" 2} 
   "children" [{"a" {"b" 3 "c" 4} "children" []}]}
  {"a" {"b" 5 "c" 6} "children" []}
  {"a" {"b" 7 "c" 8}
    "children" [{"a" {"b" 9 "c" 10} "children" []} {"a" {"b" 10 "c" 10} "children" []}]}]

I'm trying to write an algorithm to move and element within a vector. For example in the last element, it has children vector with:

"children" [{"a" {"b" 9 "c" 10} "children" []} {"a" {"b" 10 "c" 10} "children" []}]

My function is supposed to search for a specific nested map - let's say, find the map where it is the value 10 for its b property. I will locate {"a" {"b" 10 "c" 10} "children" []}. Once I found it, I need to change its location with the vector. Let's assume, that children will become:

 "children" [{"a" {"b" 10 "c" 10} "children" []} {"a" {"b" 9 "c" 10} "children" []}]

With Zipper, I was able to traverse and locate the nested map but not sure how to move it within the vector.

Here is how my zipper is created:

  (z/zipper #(contains? % "children") #(get % "children")  (fn [_ c] c) data-structure)

回答1:


As an alternative solution using specter:

  (def z [
          {"a" {"b" 1 "c" 2}
           "children" [{"a" {"b" 3 "c" 4}
                        "children" []}]}
          {"a" {"b" 5 "c" 6}
           "children" []}
          {"a" {"b" 7 "c" 8}
           "children" [{"a" {"b" 9 "c" 10}
                        "children" []}
                       {"a" {"b" 10 "c" 10}
                        "children" []}]}])


    (transform
      (walker (fn [x]
                (and
                  (vector? x)
                  (some
                    #(= 10
                        (get-in % ["a" "b"]))
                    x))))
      reverse
      z)

Returns:

[{"a" {"b" 1, "c" 2}, "children" [{"a" {"b" 3, "c" 4}, "children" []}]}
 {"a" {"b" 5, "c" 6}, "children" []}
 {"a" {"b" 7, "c" 8},
  "children"
  ({"a" {"b" 10, "c" 10}, "children" []}
   {"a" {"b" 9, "c" 10}, "children" []})}]

Notes:

  1. The walker keeps walking, so if you're looking for a once-only transformation you should adapt this somehow. I tried adding FIRST to the transform vector but it still keeps walking even after finding one of the "b"s.
  2. I tried using collect-one instead of the get-in but I did not succeed.

Feel free to edit it if you find a nicer solution. I'm still new to specter.




回答2:


This will do what I want:

(defn update-tree [editable? edit loc]
  (loop [loc loc]
    (if (z/end? loc)
    (z/root loc)
    (if (editable? (z/node loc))
      (recur (-> loc z/up (z/edit edit) z/up z/next))
      (recur (z/next loc))))))

But it is only working for this exact structure. Nesting more elements is breaking the algorithm.



来源:https://stackoverflow.com/questions/32142532/how-to-move-an-element-within-a-structure-possibly-with-zippers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!