This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-10-16
Channels
- # aws-lambda (10)
- # beginners (52)
- # boot (42)
- # cider (2)
- # cljs-dev (8)
- # cljsjs (4)
- # cljsrn (10)
- # clojars (3)
- # clojure (48)
- # clojure-conj (4)
- # clojure-dev (19)
- # clojure-italy (7)
- # clojure-norway (4)
- # clojure-russia (44)
- # clojure-spec (70)
- # clojure-uk (34)
- # clojurescript (39)
- # cursive (35)
- # data-science (11)
- # datomic (7)
- # emacs (6)
- # fulcro (2)
- # hoplon (12)
- # jobs (1)
- # juxt (18)
- # lein-figwheel (2)
- # leiningen (4)
- # luminus (9)
- # off-topic (29)
- # om (46)
- # onyx (131)
- # other-languages (24)
- # parinfer (84)
- # pedestal (10)
- # portkey (45)
- # protorepl (1)
- # re-frame (15)
- # reagent (43)
- # ring-swagger (41)
- # schema (6)
- # shadow-cljs (293)
- # slack-help (2)
- # specter (42)
Is it possible to start a search from a trees leaves? Or select the deepest nested match only?
I have a data structure like {:foo [{:bar #{:a x}} {:bar #{:b c}]}
and I want to filter :foo
by some predicate. Now I’m using (update m :foo filter-fn)
where filter-fn
is something like (filter coll pred)
.
How do I write this using Specter? Does it have some filter functionality?
@hkjels you could do something like that with zippers, but there's probably a better way
for deepest match, you could do select
with putval
at every recursive step, and then choose longest result at end
@borkdude that looks like (setval [:foo ALL remove-fn?] NONE data)
@nathanmarz I was overcomplicating it. I realized that I always need the fift level or deeper, so a simple predicate solved it
Almost what I want:
(def data {:foo [{:bar [:a]}
{:bar [:a :b]}
{:bar [:c]}]})
(setval
[:foo ALL :bar
#(seq (set/intersection #{:a}
(set %)))]
NONE
data) ;;=> {:foo [{} {} {:bar [:c]}]}
This works:
(setval
[:foo ALL
#(seq (set/intersection #{:a}
(set (:bar %))))]
NONE
data)
More learning-material would be great. I saw one of your talks on Specter yesterday @nathanmarz and was really impressed by your presentation skills
How do I update two paths in parallel, e.g. {:foo 1 :bar 2}
, (transform [#{:foo :bar} inc])
, is this possible?
@borkdude for your empty map issue:
(setval
[:foo
ALL
(multi-path
[:bar (selected? ALL (pred= :a))]
empty?)]
NONE
data)
@hkjels thanks
the wiki is much better nowadays and there was a screencast released recently
linked on the readme
@nathanmarz that’s awesome
@nathanmarz If I understand correctly, the function empty?
is a selector for the path :bar
, after the right path has been applied, so it removes the empty map?
empty? is a filter run after removal of :bar values matching the first path
ah now I get it, I read it wrong, as if :bar
and (selected? ....)
were both paths, but empty?
itself is a “path” on the value returned by the previous path
yea, that's right
that's also much more efficient than the set intersection approach
and because selected? stops the navigation, what is returned is the empty map, because no key-vals have been selected because pred= returned false
well, selected? is run on the value of :bar
it selects any vectors that have :a
in them
which is then set to NONE
, removing the key/val pair from the map
then empty? is run, removing any maps from the vector that are now empty
well, I need to check for multiple values, so I need the intersection, like this:
(setval
[:foo
ALL
(multi-path
[:bar (selected? #(empty? (set/intersection #{:a :b} %)))]
empty?)]
NONE
data)
you can do [:bar (selected? ALL #{:a :b})]
there's also no point to using selected?
with only a function
sets are implicit filter predicates in specter
interpreted equivalent to a clojure function