This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-12
Channels
- # aleph (1)
- # beginners (81)
- # boot (20)
- # cider (46)
- # cljs-dev (6)
- # cljsjs (6)
- # cljsrn (8)
- # clojars (2)
- # clojure (104)
- # clojure-berlin (3)
- # clojure-italy (4)
- # clojure-losangeles (2)
- # clojure-nl (16)
- # clojure-spec (16)
- # clojure-uk (28)
- # clojurescript (88)
- # core-logic (31)
- # cursive (8)
- # data-science (3)
- # datascript (1)
- # datomic (95)
- # docs (1)
- # emacs (6)
- # figwheel-main (24)
- # fulcro (106)
- # graphql (5)
- # hyperfiddle (2)
- # midje (2)
- # nrepl (1)
- # off-topic (14)
- # om-next (1)
- # parinfer (2)
- # pedestal (26)
- # portkey (2)
- # re-frame (11)
- # reagent (27)
- # ring (6)
- # rum (4)
- # shadow-cljs (33)
- # spacemacs (10)
- # specter (53)
- # tools-deps (17)
- # vim (31)
I have a bunch of code that looks like this (-> rows (add-foo ...) (add-bar ..))
where each of the add
functions just does an into
on the first parameter. This was working well and easy to read until I wanted to do this: (-> rows (when :flag (add-foo ...) (add-bar ...))
. I know these seems trivial, but there is a lot of code like this and it’s inside all kinds of complicated iteration code, so I’d like to maintain the “looks imperative” style. I feel like this should be an easy problem to solve but I can’t crack it. Any ideas?
@lee.justin.m looks like cond->
is kind of what you're trying to do there
hm yea that would work. (i was also trying to figure out something with into
+ concat
and then filter
out nils or something like that, but maybe cond->
is all i need)
I should probably give the XY: the real reason I’m down this path is because I’m typically looping over some structure, but that structure doesn’t have a 1-to-1 mapping: 1 thing might expand to 2 or 3 things depending on its contents. so I am doing this reduce
+ into
pattern to try to get a flat mapping
You can always do something like this:
(-> rows
(always-add-this)
(cond-> :flag (sometimes-add-this))
(always-add-this-too))
would the cond look at the truthiness of :flag
and not (:flag threaded-value)
in that case?
seems to work:
(-> [] (add-a) (cond-> false (add-b)) (cond-> true (add-c)))
=> [:a :c]
you don't need cond-> twice there
:thumbsup:
i still feel like there’s got to be a solved paradigm for map-over-a-collection where the mapping function is 1-to-many instead of the more typical 1-to-1, but this works
sure, mapcat
but maybe I don't understand what you mean by "map over a collection" "1-to-many"
right, your root issue, use mapcat
user=> (mapcat repeat [2 1 0 3 2 0] [:a :b :c :d :e :f])
(:a :a :b :d :d :d :e :e)
where in your case it's conditionals and either nil or item, rather than variable number of items
here’s a super simple example of the basic structure of what I’m doing:
(mapcat process data)
=> (1 nil 2 :even 3 nil)
(defn process [x]
[x (when (even? x) :even)])
=> #'cljs.user/process
(def data [1 2 3])
=> #'cljs.user/data
(map process data)
=> ([1 nil] [2 :even] [3 nil])
(mapcat process data)
=> (1 nil 2 :even 3 nil)
you need to change your function slightly too
instead of [x ...], [[x ...]]
then it does the same mapping and drops nils
when i say “1-to-many” i mean that process
sometimes needs to kick out 2 elements instead of 1
right, mapcat does that
oh, so what you actually need is more like (if (even? x) [x :even] [x])
then it works with mapcat
yes that’s the conclusion i came to. but if there are like 10 conditionals in building the vector, that’s not going to work
i just thought it’d be nice if there was some paradigm where instead of inserting a nil, i could just do nothing and pass the datastructure along to the next piece of code unchanged
Hello everyone, I have one more issue: This is what I am having as a input. [{:number 1, :name Adam} {:number 2, :name Berry} {:number 3, :name Gary} {:number 4, :name Thomas}] I need to process it based on the following condition: If :number = 2 exist, then print the corresponding :name. Any idea/suggestion how can I process it?
The solution you suggested are giving me nil. Do you have any idea why? I am really new in clojure. 😕
Did you see the messages between @U051SS2EU and myself after that? He corrected my code.
this is what you are saying right? (->> myVec (filter #(= 2 (:number %))) first :name)
This is what I am doing: (println "Name: ", (->> myVec (filter #(= 2 (:number %))) first :name))
hmm, I'm not getting nils with that, for the vector you previously provided. The println will return a nill though, after it has finished sending the result to standard-out
@U050PJ2EU Thank you John. It works. It is returning the value to the previous function.
surely map :name
and not :name
in both of those cases?
But yea, if you might have more than one entry with the :number 2, mapping :name would be smarter
could use
(doseq [itm d]
(when (= (:number itm) 2)
(print (:name itm))))
Thank you very much. this one works but I need to return to value to previous function. but don't know how to return this value. do you have any idea how to return it?
Sorry I didn't get back to you earlier,
(reduce (fn [prev d]
(if (= (:number d) 2)
(conj prev (:name d))
prev))
[]
d)
That reduce will return a vector of the names
where d is your data
also this is if you only want to print, if you need the return values then my suggestion isn't a good choice
I’m pondering whether I would a) wrap lots and lots of specs with nilable
or b) remove all keys with nil values from my maps before validation.
There's no requirement to spec a raw wire payload. I usually clean up a bit, then apply better simpler specs
In that case the follow up question: what’s the idiomatic way to do that for nested maps?
I mean, I’ve seen walk
and reduce
solutions and written one terrible recursion version myself but I can’t say I feel 100% confident about any of those. I’d like to hear other peoples favourites. 🙂
Or actually I’d like to hear that there’s something idiomatic in core which does just that.
postwalk would be the most general and idiomatic way (checking for map?
and removing entries with nil values)
really, the best path is to avoid ever putting the nils in there in the first place
I’m trying to use the a java.time method DateTimeFormat.parse (https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#parse-java.lang.CharSequence-java.time.temporal.TemporalQuery-), which takes a method reference that would be expressed like LocalDate::from in java. I’m unsure how interop works in this case.
LocalDate::from is a syntax to create a java.util.function.Function instance
(which internally calls the from method on LocalDate)
https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalQuery.html reify that interface and pass it in
@hiredman thanks!
(def local-date
(reify TemporalQuery
(queryFrom [_ ^TemporalAccessor temporal]
(LocalDate/from temporal))))
(.parse (formatter "MM/dd/uuuu") "03/27/2016" local-date)
say you're very ambitious and want to make a website that scrapes all the venue websites and band websites for local venues and bands to make a complete calendar of bands & events. what sort of clojure tools for scraping websites are there?
I've used both htmlunit (which is basically a headless web browser written in java designed for testing websites) and the webdriver rest api thing to drive a headless firefox in a docker container
I've had good luck using enlive - it's mainly meant for templating but it worked for me when the page structure was predictable
and yeah for pages that require js you'll need one of those browser driven things likely
if you are lucky, a lot of react based sites these days serve up a big blob of json that you can slurp out and ignore the markup
that's handy
Oh that's an idea. Depending on how nice the data is. wow making a headless browser to process data. what has the world come to haha
don't know anything about htmlunit. i recall enlive does have some scraping ability now! hmms.