This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-23
Channels
- # announcements (11)
- # babashka (35)
- # beginners (110)
- # calva (2)
- # cider (46)
- # clara (5)
- # clj-kondo (29)
- # cljdoc (4)
- # cljsrn (59)
- # clojure (163)
- # clojure-brasil (3)
- # clojure-europe (24)
- # clojure-italy (2)
- # clojure-nl (10)
- # clojure-sweden (1)
- # clojure-uk (36)
- # clojurescript (58)
- # conjure (24)
- # cursive (19)
- # data-science (14)
- # datascript (1)
- # datomic (10)
- # docker (3)
- # expound (6)
- # figwheel-main (17)
- # fulcro (16)
- # graalvm (1)
- # leiningen (9)
- # malli (11)
- # off-topic (22)
- # parinfer (1)
- # pathom (1)
- # re-frame (18)
- # reagent (18)
- # reitit (3)
- # ring (3)
- # shadow-cljs (8)
- # spacemacs (3)
- # specter (79)
- # sql (20)
- # tools-deps (25)
- # vim (4)
- # xtdb (8)
hey folks, given a vector of vectors of integers, and a separate vector of integers to remove, how can I remove all integers from the sub-vectors that are in the separate vector?
(def to-remove [ 4 5 6 ])
(def coll [ [1 2 4] [3 5 8 ] [6] [] ])
(specter/transform [(specter/filterer not-empty) specter/ALL ..?.. ] specter/NONE coll)
;; => [ [1 2] [3 8] [] [] ]
Seems like this works, is there a more efficient way to write it?
(specter/setval [specter/ALL specter/ALL (fn [val] (some #(= val %) to-remove))] specter/NONE coll)
Might be nicer if you made to-remove
a set, then it is just (to-remove val)
or replace fn
form with #(to-remove %)
Hi, sorry if this is a FAQ, but how can I navigate to a map, and then filter the entries in the map, based on certain nested values in the values?
Here’s what I’m doing in “plain old Clojure” (plus Medley) that I’m curious how to translate to Specter:
(->> (db/read "db")
(:technologies)
(medley/filter-vals
(fn [tech] (some (fn [rec] (rec "ratified"))
(get tech "recommendations")))))
not sure it's the most straightforward approach, but you could probably use:
[:technology MAP-VALS]
for the path. in your transform function:
• return the original value to keep it
• return spec/NONE to remove a valueYeah, I left if off but when I ran the above code, the last form in the thread-last form was keys
[:technology MAP-VALS (fn [tech] (some (fn [rec] (rec "ratified"))
(get tech "recommendations")))]
i'm not specter expert either ¯\(ツ)/¯
Wait… that’ll navigate to the results of the predicate, right? But I want the map under :technologies
, just filtered
I’m very new to Specter but I’d think it’d have something roughly equivalent to Medley’s filter-vals
(which filters a map by applying a predicate to the vals in the map, and returns a map containing the matching entries)
Right! I tried that but had trouble with it. Thought maybe I just didn’t understand it. I’ll try again… brb
imo, specter is much more useful if you're transforming or setting data in a deeply nested data structure. if you're just drilling into a nested data structure, I usually just use the normal clojure functions
But I’d like to build up my own intuition as to when to use Specter, by seeing what it’s like to use it in cases like this
:thumbsup:
Also, I had to walk a Clojure newbie through the above code and it was non-trivial to explain. I think the path concept could maybe be much more straightforward for folks new to Clojure and Lisps.
i'm only a specter novice, so there's probably a very straightforward way to do it that I don't know about
Trying this:
(select [:technologies
(filterer MAP-VALS "recommendations" ALL "ratified")
MAP-KEYS]
db)
getting: java.lang.ClassCastException: "class java.lang.String cannot be cast to class java.util.Map$Entry…
specter doesn't recognize strings as map keys like it does for keywords
I think "recommendations" needs to be (keypath "recommendations")
hmmm, maybe it does
filterer is complaining because it's turning the map into a sequence
maybe something like:
(spec/select [:technologies
(spec/filterer (spec/nthpath 1) "recommendations" spec/ALL "ratified")
ALL
(spec/nthpath 0)]
db)
huh, that’s surprising. I wonder why it’s doing that. I’d think that’d be antithetical to Specter’s general behavior of leaving types as-is
interesting… this “works”, but the result is incorrect:
(select [:technologies
(filterer (nthpath 1) "recommendations" ALL "ratified")
MAP-KEYS]
db)
> with the path yields anything other than an empty sequence.
the path is probably yielding false
or whatever is in the ratified key
does the ratified key exist even for unratified recommendations?
right. but most of the maps in the sequences that correspond to the "recommendations" keys do not have the key "ratified"; only a few do. I’m trying to find those technologies that have recommendations that have been ratified
this seems to work:
(def data {:technologies
{0 {"recommendations" [{"ratified" true}]}
1 {"recommendations" [{"ratified" false}]}
2 {"recommendations" []}}})
(spec/select [:technologies
(spec/filterer (spec/nthpath 1) "recommendations" spec/ALL "ratified" identity)
spec/MAP-KEYS
;; ALL
;;(spec/nthpath 0)
]
data)
the above will return [0]
so without identity and removing filterer:
(def data {:technologies
{0 {"recommendations" [{"ratified" true}]}
1 {"recommendations" [{"ratified" false}]}
2 {"recommendations" []}}})
(spec/select [:technologies
ALL
(spec/nthpath 1) "recommendations" spec/ALL "ratified"
;; spec/MAP-KEYS
;; ALL
;;(spec/nthpath 0)
]
data)
you get [true false]
basically, it can navigate to the "ratified" key
I also removed the filterer
and the path exists if it can navigate there
so filterer will keep paths that it can navigate to, even if the value it navigates to is falsey
so identity is the simplest function that I can think of to filter based on truthiness
I think filterer has the right design, but it is a little surprising at first
(some? false)
=> true
actually, boolean
is probably clearer
(def data {:technologies
{0 {"recommendations" [{"ratified" true}]}
1 {"recommendations" [{"ratified" false}]}
2 {"recommendations" []}}})
(spec/select [:technologies
(spec/filterer (spec/nthpath 1) "recommendations" spec/ALL "ratified" boolean)
spec/MAP-KEYS
]
data)
some?
's doc string is correct:
clojure.core/some?
[x]
Added in 1.6
Returns true if x is not nil, false otherwise.
Anyway, I still don’t quite get filterer
— but a prerequisite to getting it is seeing what works. Which I’ve got now. Thank you so much!