This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-12-11
Channels
- # adventofcode (52)
- # announcements (3)
- # aws (2)
- # babashka (36)
- # babashka-sci-dev (4)
- # beginners (69)
- # biff (45)
- # calva (9)
- # cider (3)
- # clara (8)
- # clj-kondo (24)
- # clojure (20)
- # clojure-dev (12)
- # clojure-europe (12)
- # clojurescript (2)
- # conjure (1)
- # emacs (17)
- # lsp (69)
- # malli (12)
- # off-topic (32)
- # polylith (2)
- # re-frame (4)
- # releases (2)
- # scittle (6)
- # shadow-cljs (21)
- # tools-deps (10)
- # vim (11)
- # xtdb (11)
This is a very basic question, for some reason I’m stumped on the easy way to do this:
(defn get-ids
[oracles]
(doseq [i oracles]
(when (contains? i :Oracles)
(get-ids (i :Oracles)))
(when (contains? i :Categories)
(get-ids (i :Categories)))
(print (str (i :$id) "\n"))))
That final print
I want that only to happen if neither of the when
s fired. Suggestions?Ok - as often happens, shortly after getting the question out a solution comes to me:
(defn get-ids
[oracles]
(doseq [i oracles]
(if (or (contains? i :Oracles) (contains? i :Categories))
(do (when (contains? i :Oracles) (get-ids (i :Oracles)))
(when (contains? i :Categories) (get-ids (i :Categories))))
(print (str (i :$id) "\n")))))
Does this seem sensible?I don’t think that works, do returns the last value so that first when is ignored
I think you want something like https://clojuredocs.org/clojure.core/cond
I will take a look at cond. It does seem to be working though - the first when isn’t ignored because it’s calling itself. I’m looking to execute none, one, or both of the when statements when they are true.
But I am relying on side-effects here, which is probably bad practice
Yeah, ”ignored” was a bad choice of words; the do invokes it (for side effects) but returns the value of the final form
Yeah - I initially tried to do this with recur as a proper recursive function, but the data structure that I’m parsing isn’t super-nicely formed and I don’t control it.
The output of those prints (which are just a side-effect) is what I’m trying to capture. I’m going to dig a little deeper and see if I can figure out how to make it pure.
Ok - this is better:
(defn get-ids [oracles]
(flatten
(map (fn [i]
(if (or (contains? i :Oracles) (contains? i :Categories))
(concat
(if (contains? i :Oracles) (get-ids (i :Oracles)) ())
(if (contains? i :Categories) (get-ids (i :Categories)) ()))
(i :$id)))
oracles)))
(defn get-ids
[oracles]
(doseq [i oracles]
(let [print-id! #(print (str (i :$id) "\n"))]
(cond
(contains? i :Oracles)
(do
(get-ids (i :Oracles))
(print-id!))
(contains? i :Categories)
(do
(get-ids (i :Categories))
(print-id!))))))
(defn get-ids [oracles]
(flatten
(map (fn [i]
(if (or (i :Oracles) (i :Categories))
(concat (some-> (i :Oracles) (get-ids))
(some-> (i :Categories) (get-ids)))
(i :$id)))
oracles)))
and you probably don't want flatten unless you want to flatten recursively (surprising behavior)
(defn get-ids [oracles]
(for [i oracles
thing (if (or (i :Oracles) (i :Categories))
(concat (some-> (i :Oracles) (get-ids))
(some-> (i :Categories) (get-ids)))
(i :$id))]
thing))
(defn get-ids [oracles]
(for [i oracles
thing (if (or (i :Oracles) (i :Categories))
(concat (get-ids (i :Oracles))
(get-ids (i :Categories)))
(i :$id))]
thing))
(defn get-ids [oracles]
(for [oracle oracles
id (cond
(i :Oracles)
(get-ids (i :Oracles))
(i :Categories)
(get-ids (i :Categories))
:else
[(i :$id)])]
id))
The cond won't work, it will short circuit right after the first condition if it's true, right?
(Even if the second one is also true) edit: Sorry, that's what you said, I'm on the phone so didn't see it
I think a lot of information is missing, e.g. if i
is a map it would simplify stuff quite a bit, but using flatten, map and concat together in such a short piece of code is definitely a code smell. mapcat could help and I think you could squeeze a juxt in there as well.
Thanks guys, some good ideas to think on. It does have both Oracles and Categories in various cases (at the same level) - so I think that’s a big part of what’s making it tricky. My last post does work, but it doesn’t use tail recursion which is still bugging me.
i have a nested map like:
{:size 48381165,
:children {:a {:size 94853, :children {:e {:size 584, :children {:filesizes 584}}, :filesizes 94269}},
:d {:size 24933642, :children {:filesizes 24933642}},
:filesizes 23352670}}
What is the simplest way to collect all the values of :size keys into a vector
Checkout tree-seq
. This looks like advent-of-code. There are a few solutions in https://clojurians.slack.com/archives/C0GLTDB2T/p1670392240040349
thanks, trying to struggle myself before looking at other peoples answers, but probably need to come back to this one.
I’m a beginner myself and I tried to come up with a solution for you, as a learning exercise. But it uses recursion so I think the above mentioned tree-seq
, is probably the right way to go about this. Thanks @U1Z392WMQ for bringing that to light!
But here’s the code, maybe you find it helpful in some way. You can use also use flatten
to turn the nested array into a single dimension array, if needed.
(defn get-sizes [{size :size :as nodes}]
(let [not-nil? (complement nil?)]
(if (not-nil? (get nodes :children))
(let [child-node-sizes (for [child-node (vals (:children nodes))
:when (not-nil? (:size child-node))]
(get-sizes child-node))]
(vec (concat [size] child-node-sizes)))
[size]))
tree-seq
can do the job. But it is pretty contorted. I would suggest taking this as opportunity to learn to use clojure.walk
or clojure.zipper
.
Otherwise either loop
->`recur` . or copy the basic strategy of tree-seq
, which is recursively wraps a lazy-seq
around cons
& mapcat
.
@U04D4J04PFW (complement nil?)
is already in the stdlib, it’s called some?
Also in these examples you don’t even need it, you could just pass directly to if
(if (get nodes :children)
it checks for nil
and false
@U89SBUQ4T Thanks for pointing that out. 🙏:skin-tone-2:
Hi, I just started to use speclj. I'm using the autotest feature using lein spec -a
. It runs the tests fine when I save the core_spec.clj file but it does not autotest when I change and save the core.clj file. Any tips on how to make this work as well?
Hi, I am a beginner. I am trying to deploy But I don't know what's happening here. Is it deployed? can someone help me
looks like instead of deploy the script start a repl. what is inside of deploy.sh script?
@U04V4KLKC It's happening after the installation of the Clojure Command Line Interface (CLI). Is there any way to remove cli?
i don't know what you are doing. there are infinite ways to deploy Clojure applications
@U04V4KLKC how can I uninstall CLI?
@U11BV7MTK before installation the error was like this
@U11BV7MTK what should I do? how can I solve this error?
i have no idea how you installed the clojure cli nor do we know what ./deploy.sh
is trying to do
there installation instructions here: https://clojure.org/guides/install_clojure If you installed it a different way can you tell us how?
@U11BV7MTK The guide I followed had no instructions to install the cli for deployment.
@U11BV7MTK I have installed cli using this guide https://ericnormand.me/guide/how-to-install-clojure
linux guide
but we dont' know what ./deploy.sh
is attempting to do so cannot really help you further
@U11BV7MTK ok, Thanks brother
Please have a look
if you are getting a repl, then the clj -A:uberjar:package
command doesn't seem to be doing what you want
@U11BV7MTK sclj -A:uberjar:package
script start a repl
i'm not sure who made these aliases uberjar
and package
. Do you know anyone else connected to the codebase? At this point you need to read the code to see what it is attempting to do and see what's up
@U11BV7MTK ok, Thanks a lot sir