This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-03
Channels
- # adventofcode (49)
- # bangalore-clj (1)
- # beginners (56)
- # berlin (1)
- # chestnut (6)
- # cljs-dev (5)
- # clojure (48)
- # clojure-greece (29)
- # clojure-russia (3)
- # clojure-spec (5)
- # clojure-uk (3)
- # clojurescript (28)
- # cursive (25)
- # emacs (3)
- # fulcro (123)
- # hoplon (2)
- # klipse (6)
- # off-topic (146)
- # om (11)
- # re-frame (29)
- # reagent (7)
- # reitit (3)
- # specter (11)
- # unrepl (4)
- # yada (3)
hi, i have a quick question. I want to recursively search for an element in a data-structure (maps, that have lists, that have maps, etc), then do a setval before/after the element i found so I have this test data structure
#:designer{:cur-form-def #:form{:id #uuid"4979e704-5047-48cf-bfe3-fdf9ca58bae8",
:name "New Form",
:description "Description",
:version 1,
:groups [#:group{:id #uuid"d865ab2f-d114-4853-9a37-592a2c941152",
:title "Page 1",
:type :page,
:layout :vertical,
:subgroups [#:group{:id #uuid"237a7f3e-702e-4b63-8b4e-5df4da205e22",
:name "row1",
:type :row,
:layout :horizontal,
:fields [#:field{:id #uuid"b9a2c9ea-2647-48d3-ab26-4c2a115d7b6f",
:name :newfield,
:label "New Fuekd",
:type :text}]}]}]}}
And I want to find the :newfield by its id and jam a new map in the containing vector after :newfield
so I do the following:
(sp/setval [:designer/cur-form-def
:form/groups
sp/ALL
(sp/walker #(= (:field/id %) #uuid "b9a2c9ea-2647-48d3-ab26-4c2a115d7b6f"))
sp/AFTER-ELEM
] [{:test :newfield}] appdb)
which gives me this:
#:designer{:cur-form-def #:form{:id #uuid"4979e704-5047-48cf-bfe3-fdf9ca58bae8",
:name "New Form",
:description "Description",
:version 1,
:groups [#:group{:id #uuid"d865ab2f-d114-4853-9a37-592a2c941152",
:title "Page 1",
:type :page,
:layout :vertical,
:subgroups [#:group{:id #uuid"237a7f3e-702e-4b63-8b4e-5df4da205e22",
:name "row1",
:type :row,
:layout :horizontal,
:fields [([:field/id
#uuid"b9a2c9ea-2647-48d3-ab26-4c2a115d7b6f"]
[:field/name :newfield]
[:field/label "New Fuekd"]
[:field/type :text]
The walker selector worked fine, but now :group/fields has gone from a vector with a single map to a vector, that has a single list of k/v pairs including the new one. So I’m obviously doing somethign wrong lol. When if leave off the AFTER-ELEM, the map is set as one would expect but replaces the one that was ‘found’
I’ve figured that I need to ‘go up/out’ of the map to get back to the vector, at this point, just not sure how@eoliphant you need to do something similar to what I showed you before with before-index-dynamic
, except navigate after the index of the target element
you could also use zippers for this task, see https://github.com/nathanmarz/specter/wiki/Using-Specter-With-Zippers
hmm, ok so would it be something more like creating a recursive-path navigator instead of using walker?
definitely
make a recursive path navigating to every "group" map, then navigate from there to the position next to your target element
there are really very few cases that justify the use of walker
it traverses map keys, map key/value pairs, dives into record fields, all of which causes it to be much slower than necessary as well as lead to surprising bugs
and i see your point, walker is quick-and-dirty but far from optimal since I know specifically what I need to ’walk;
hi, I’m trying something like this:
(def find-field
(sp/recursive-path [uuid] p
(sp/cond-path
(sp/keypath :group/subgroups) [sp/ALL p]
(sp/keypath :group/fields) [sp/ALL p]
#(= (:field/id %) uuid) sp/STAY)))
and calling it like so
(sp/select [:designer/cur-form-def
:form/groups
(find-field #uuid "b9a2c9ea-2647-48d3-ab26-4c2a115d7b6f" )
]
appdb)
I’ve tried it with and without the keypath
call but I’m getting a “Don’t know how to create ISeq from: clojure.lang.Keyword ” in both cases