Fork me on GitHub
#beginners
<
2022-12-11
>
Matthew Twomey05:12:16

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 whens fired. Suggestions?

Matthew Twomey05:12:36

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?

lassemaatta05:12:27

I don’t think that works, do returns the last value so that first when is ignored

Matthew Twomey05:12:55

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.

Matthew Twomey05:12:17

But I am relying on side-effects here, which is probably bad practice

lassemaatta05:12:07

Yeah, ”ignored” was a bad choice of words; the do invokes it (for side effects) but returns the value of the final form

Matthew Twomey05:12:00

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.

Matthew Twomey05:12:27

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.

Matthew Twomey06:12:14

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)))

emccue06:12:21

(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!))))))

emccue06:12:22

so thats maintaining the side effect part

emccue06:12:00

but you can also abuse the fact that nil is an empty sequence here

emccue06:12:00

(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)))

emccue06:12:50

and you probably don't want flatten unless you want to flatten recursively (surprising behavior)

emccue06:12:53

(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))

emccue07:12:38

and then oracles being nil means empty sequence so...

emccue07:12:57

(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))

emccue07:12:41

maybe clearer without the or

emccue07:12:33

(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))

emccue07:12:58

...I think that would work

emccue07:12:16

so long as no Oracles and Categories at same time. its 2am so apolg

👍 1
pavlosmelissinos07:12:49

The cond won't work, it will short circuit right after the first condition if it's true, right?

pavlosmelissinos07:12:19

(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

pavlosmelissinos07:12:53

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.

Matthew Twomey17:12:02

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.

Anssi Kittilä12:12:52

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

tschady13:12:11

Checkout tree-seq. This looks like advent-of-code. There are a few solutions in https://clojurians.slack.com/archives/C0GLTDB2T/p1670392240040349

Anssi Kittilä13:12:54

thanks, trying to struggle myself before looking at other peoples answers, but probably need to come back to this one.

Vernon13:12:23

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]))

🙌 1
skylize14:12:43

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.

👍 2
Miķelis Vindavs16:12:44

@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)

👍 1
Miķelis Vindavs16:12:56

it checks for nil and false

Vernon02:12:17

@U89SBUQ4T Thanks for pointing that out. 🙏:skin-tone-2:

Eric Uitbeijerse13:12:57

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?

Falak Shair17:12:07

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

delaguardo17:12:32

looks like instead of deploy the script start a repl. what is inside of deploy.sh script?

Falak Shair17:12:20

@U04V4KLKC It's happening after the installation of the Clojure Command Line Interface (CLI). Is there any way to remove cli?

delaguardo17:12:41

i don't know what you are doing. there are infinite ways to deploy Clojure applications

Falak Shair17:12:33

@U04V4KLKC how can I uninstall CLI?

dpsutton18:12:42

Why do you think uninstalling a program will help you?

Falak Shair18:12:09

@U11BV7MTK before installation the error was like this

dpsutton18:12:36

And you’d prefer to return to that error?

Falak Shair18:12:21

@U11BV7MTK what should I do? how can I solve this error?

dpsutton18:12:43

i have no idea how you installed the clojure cli nor do we know what ./deploy.sh is trying to do

dpsutton18:12:53

do you know how you installed the cli?

dpsutton18:12:00

there installation instructions here: https://clojure.org/guides/install_clojure If you installed it a different way can you tell us how?

Falak Shair18:12:13

@U11BV7MTK The guide I followed had no instructions to install the cli for deployment.

dpsutton18:12:29

can you link the guide you followed?

dpsutton18:12:17

did you run `

brew install clojure/tools/clojure
?

dpsutton18:12:04

or these instructions?

dpsutton18:12:16

great. so that installed it just like the linked document i sent you

dpsutton18:12:22

so you have the programs you need.

dpsutton18:12:37

but we dont' know what ./deploy.sh is attempting to do so cannot really help you further

dpsutton18:12:49

you have installed the Clojure CLI correctly

dpsutton18:12:04

if you are willing to share the contents of deploy.sh we can help.

Falak Shair18:12:48

Please have a look

dpsutton18:12:08

what happens if you run clj -Spom and then clj -A:uberjar:package ?

dpsutton18:12:29

if you are getting a repl, then the clj -A:uberjar:package command doesn't seem to be doing what you want

Falak Shair18:12:09

@U11BV7MTK sclj -A:uberjar:package script start a repl

dpsutton18:12:41

yeah the repl seems to be what you are seeing in the original script.

dpsutton18:12:19

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

Falak Shair18:12:17

@U11BV7MTK ok, Thanks a lot sir