Fork me on GitHub
#beginners
<
2022-01-16
>
popeye05:01:09

i was checking use of apply and found this example (map #(apply max %) [[1 2 3][4 5 6][7 8 9]]) where I get expected result, what if the collection is in vector of vector i,e (map #(apply max %) [[[1 2 3][4 5 6][7 8 9]]]) how can i get maximum ib this case ?

lsenjov05:01:03

The maximum of what, exactly? All the results?

popeye07:01:53

yes should be (3 6 9)

didibus07:01:15

You can call first to get it out of the additional vector:

(->> [[[1 2 3] [4 5 6] [7 8 9]]]
     (first)
     (map #(apply max %)))

popeye07:01:49

first will not be choice if it is in

`[[[[[]]]]]

didibus07:01:13

I would say that in general, your input collection shouldn't be of arbitrary shape like that. Whatever would be providing or returning such vector is probably the code you'd want to fix.

popeye07:01:08

no i am just in case asking from curiosity. 🙂 if my input is in such a away

didibus08:01:30

Hum, to do it so it's still lazy isn't as pretty

didibus08:01:34

(->> [[[[[[[1 2 3] [4 5 6] [7 8 9]]]]]]]
     (tree-seq sequential? identity)
     (rest)
     (filter #(and (vector? %) (not (sequential? (first %)))))
     (map #(apply max %)))

didibus08:01:19

And if you don't mind not being lazy, you can use loop/recur which can do it in an eager way say like so:

(->> (loop [coll [[[[[[[1 2 3] [4 5 6] [7 8 9]]]]]]] prev-coll nil]
       (if (sequential? (first coll))
         (recur (first coll) coll)
         prev-coll))
     (map #(apply max %)))

didibus08:01:01

Ah, here, I think I found something slightly nicer:

(->> [[[[[[[1 2 3] [4 5 6] [7 8 9]]]]]]]
     (iterate first)
     (take-while (comp sequential? first))
     (last)
     (map #(apply max %)))

popeye08:01:54

just trying a way on walk and found this . What is your thoughts on this ?

(flatten (prewalk  #(apply max %) [[[[[[[1 2 3][4 5 6][7 8 9]]]]]]]))

didibus08:01:54

I think that works as well

didibus08:01:41

I had thought about using walk at first, you can see that with my use of tree-seq. If you look at the implementation of flatten itself, you'll see it uses tree-seq itself a bit like I did in my first approach

popeye08:01:29

thanks, but I will take a look on your code 🙂

didibus08:01:07

But I wouldn't say your approach is any worse than any of the ones I wrote.

popeye09:01:04

just have the question , i was checking prewalk-demo and postwalk-demo , and how it opeartes the function, but did not get whey (flatten (postwalk #(apply max %) [[[[[[[1 2 3][4 5 6][7 8 9]]]]]]])) gives eeror

didibus09:01:11

Because apply takes a seqable, but poswalk does depth first traversal, which means the first element is 1 and that's not a seq, it is a long.

didibus09:01:27

Try this and see that it throws the same error: (apply max 1)

popeye09:01:27

in prewalk also it apply the function on 1 right?

user=> (prewalk-demo  [[[[[[[1 2 3][4 5 6][7 8 9]]]]]]])
Walked: [[[[[[[1 2 3] [4 5 6] [7 8 9]]]]]]]
Walked: [[[[[[1 2 3] [4 5 6] [7 8 9]]]]]]
Walked: [[[[[1 2 3] [4 5 6] [7 8 9]]]]]
Walked: [[[[1 2 3] [4 5 6] [7 8 9]]]]
Walked: [[[1 2 3] [4 5 6] [7 8 9]]]
Walked: [[1 2 3] [4 5 6] [7 8 9]]
Walked: [1 2 3]
Walked: 1
Walked: 2
Walked: 3
Walked: [4 5 6]
Walked: 4
Walked: 5
Walked: 6
Walked: [7 8 9]
Walked: 7
Walked: 8
Walked: 9

popeye09:01:42

it also apply function on 1, 2, 3

noisesmith17:01:00

(cmd)(user=> (defn stupid-max
               [coll]
               (->> coll
                    (tree-seq coll? seq)
                    (filter coll?)
                    (filter #(every? number? %))
                    (map #(apply max %))))
#'user/stupid-max
(cmd)user=> (stupid-max [[[[1 2 3]] [4 5 6] 7 [8 9]] [10 11 12]])
(3 6 9 12)

noisesmith17:01:11

prewalk is good if you want a consistent transform across all levels of the structure, but that's not what you want here what you want is to apply your function to arbitrary parts of the structure that meet a predicate (eg. a collection of numbers)

noisesmith17:01:55

also wanting code to ignore input structure is a terrible smell (but has valid use cases, eg. where the input is badly structured or inconsistent) - if it has to happen it should be an isolated (and dedicated) layer of your code that doesn't mix in with application logic

didibus21:01:05

Prewalk will not walk to the numbers 1,2 and 3, because the way prewalk and postwalk work is recursive. What the function returns becomes the new node.

user=> (clojure.walk/prewalk #(do (println "Walked: " %) (let [ret (apply max %)] (println "Returned: " ret) ret)) [[[[[[[1 2 3][4 5 6][7 8 9]]]]]]])
Walked:  [[[[[[[1 2 3] [4 5 6] [7 8 9]]]]]]]
Returned:  [[[[[[1 2 3] [4 5 6] [7 8 9]]]]]]
Walked:  [[[[[1 2 3] [4 5 6] [7 8 9]]]]]
Returned:  [[[[1 2 3] [4 5 6] [7 8 9]]]]
Walked:  [[[1 2 3] [4 5 6] [7 8 9]]]
Returned:  [[1 2 3] [4 5 6] [7 8 9]]
Walked:  [1 2 3]
Returned:  3
Walked:  [4 5 6]
Returned:  6
Walked:  [7 8 9]
Returned:  9
[[[3 6 9]]]

didibus21:01:30

But I just realized that your solution is very accidental, if you have an uneven number of brackets it won't work anymore

didibus21:01:03

user=> (clojure.walk/prewalk #(apply max %) [[[[[[1 2 3][4 5 6][7 8 9]]]]]])
java.lang.ClassCastException: class clojure.lang.PersistentVector cannot be cast to class java.lang.Number (clojure.lang.PersistentVector is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')

erre lin13:01:26

Hello, I have a basic question about Reitit routes syntax. I want to use a handler function which is NOT anonymous and can accept args, something like below:

(def routes
  [["/home" (handler-one arg-1)]
   ["/about" (handler-two arg-1 arg-2)]
  ]
The above syntax will cause error. How to correct it? I haven't found such examples. Doc shows how to use anonymous functions as handlers with decomposed map as args. Can what I described above be possible? If yes, could anyone show me a simple example? Thanks so much for your help

erre lin13:01:10

Thank you. This is a good suggestion. Yet the problem is ["/home" (hander-one arg-1)] seems wrong indeed. My bad for not making it clear. Most examples are like ["/home" handler] where handler is either an anonymous function or a function that receives no args. Thus I'm. a bit confusing how to write a named function with args and use it in a specific route. Thanks for your quick response again:smile:

lassemaatta13:01:45

I'm improvising here, but I'd guess you could try one of these approaches

(defn foo
  [a b req]
  {:status 200 :body "ok"})

(defn bar
  [a b]
  (fn [req]
    {:status 200 :body "ok"}))

(defn no-extra-args
  [req]
  {:status 200 :body "ok"})

(def routes
  ["/with-partial" (partial foo 1 2)
   "/nested-fn"    (bar 1 2)]
   "/plain-fn"     no-extra-args
   "/anonymous"    (fn [req] {:status 200 :body "ok"}))

👍 1
lassemaatta13:01:45

foo is an example of how you can use partial to supply some of the parameters while building routes and the final req parameter is provided by reitit at runtime when the request actually occurs

👍 1
lassemaatta13:01:31

I'm assuming here arg-1 and arg-2 are some constants you know beforehand

erre lin15:01:29

Sorry for the late reply. Your suggestions look excellent. I'll definitely try them out. Thank you so much for the help:+1:

👍 1
popeye17:01:27

saw this code one of the doc is this just a way where used 2 colons as a key? or it is a purpose ?

{::data-source {:db-spec db-spec}
 ::get-article-by-id {:data-source (ig/ref ::data-source)}
 ::get-article-handler {:get-article-by-id (ig/ref ::get-article-by-id)}
 ::router {:route->handler {:get-article (ig/ref ::get-article-handler)}}}

andy.fingerhut18:01:03

You are welcome to ask on #beginners of course, but in case you were unaware of it I wanted to mention the Clojure cheatsheet, which has a section attempting to describe the meaning of most non-alphabetic characters you will come across in Clojure: https://clojure.org/api/cheatsheet

andy.fingerhut18:01:30

That section (bottom left of the sheet) has a link "guide" at the top that links to a longer form article with more description of each thing.

randomm char17:01:19

But there's no link to :: for a description from what I can tell it has something to do with keywords? If I search on the cheatsheet for :: I get "::in-cur-namespace ::namespace-alias/kw" with no links to anywhere? Am I missing something here?

andy.fingerhut17:01:44

I agree that the cheatsheet does not give links to every possible thing that one can possibly imagine giving a link for. There is a link from the word "literals:" just before the examples of different kinds of keyword syntax to this page, which explains more: https://clojure.org/reference/reader#_literals

andy.fingerhut17:01:45

I have been maintaining the cheatsheet for about 8 years now. If you have suggestions of links you wish were there, feel free to create an issue for this repo: https://github.com/jafingerhut/clojure-cheatsheets

noisesmith17:01:40

it's a shorthand for a keyword namespaced by the current ns:

user=> ::foo
:user/foo

noisesmith17:01:54

by context, that looks like integrant, where you are expected use namespaced keys for components (the namespacing makes things easier, because then you know where various parts of that map come from)

👍 1