This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-11-06
Channels
- # announcements (3)
- # babashka (1)
- # beginners (26)
- # calva (1)
- # cider (17)
- # clj-commons (16)
- # clj-kondo (11)
- # clojure (21)
- # clojure-europe (9)
- # clojure-norway (1)
- # clojure-portugal (2)
- # clojure-spec (8)
- # clojure-uk (4)
- # clojurescript (35)
- # datomic (5)
- # emacs (9)
- # figwheel-main (15)
- # fulcro (26)
- # honeysql (1)
- # lsp (5)
- # off-topic (2)
- # polylith (1)
- # rdf (6)
- # re-frame (4)
- # reagent (15)
- # reitit (9)
- # releases (2)
- # shadow-cljs (4)
- # sql (25)
- # squint (2)
- # xtdb (7)
Hey, I've got a data structure (which I cannot change) like
[{:identifier "abc" :other-key-1 "abc"}
{:identifier "SELF" :content {}}
{:identifier "def" :other-key-2 []}]
I would like to do the following:
1. Determine if there is exactly one item in the vector of maps which has the :identifier "SELF"
.
2. For that item, determine if there exists the key :content
3. Make sure its value is a map (whose properties I also would like to spec)
Can anyone think of a good way of doing this in spec or give me pointers of how to think about this?(require '[clojure.spec.alpha :as s])
(def d [{:identifier "abc" :other-key-1 "abc"}
{:identifier "SELF" :content {}}
{:identifier "def" :other-key-2 []}])
(defn- self-id? [{:keys [identifier]}] (= "SELF" identifier))
(s/def :self/identifier #{"SELF"})
(s/def :self/content (s/keys)) ; TBD
(s/def ::self (s/keys :req-un [:self/identifier :self/content]))
(s/def ::not-self (s/or :!m (complement map?) :!self (complement self-id?)))
(s/explain-data ::self (first (filter self-id? d)))
(s/def ::d (s/and (s/coll-of map?)
(s/cat :before (s/* ::not-self)
:self ::self
:after (s/* ::not-self))))
(s/explain-data ::d d)
(s/conform ::d d)
; {:before [[:!self {:identifier "abc", :other-key-1 "abc"}]],
; :self {:identifier "SELF", :content {}},
; :after [[:!self {:identifier "def", :other-key-2 []}]]}
> "...pointers of how to think about this"
Thing of it like regex: you want to match 0 or more non-self maps, followed by a self map, followed by 0 or more non-self maps.
(An s/not
spec would've been handy here.)
Yeah, like a regex. It totally makes sense. The docs even stated this, but just didn't come up with this in the moment.
> An s/not
spec would've been handy here.
:thinking_face: Interesting. I see, for the :not-self
...
Yeah, I would've liked to do (s/not ::self)
rather than having to define a negation of ::self
manually, because now they could drift out of sync.
Yes. I have an intuition that it should generally be possible to make such a thing. One would need to account for the different, uhm, don't know the name, the different things like s/keys
, s/cat
and so on. The negation of the s/keys
was an s/or
with complement
. Not in the mood to solve that puzzle right now, but certainly an interesting challenge 😀