Fork me on GitHub
#beginners
<
2023-01-05
>
Tema Nomad07:01:01

what is the standard solution to render clojure API json response with ring? ring-json lib?

dumrat07:01:15

That's what I have seen used in many places

👍 2
Patrick Winter08:01:30

I've the following dependency graph:

(def dependency-graph  {:n3 #{:n1 :n2}
                        :n4 #{:n3}})
Each element in the set is a direct dependency of a node (the map key). How would I invert this data structure in a functional way so it describes the required-by relationship instead of the depends-on relationship? I've tried something like this, but I would need to additionally merge all the maps at each reduce step:
(reduce {} (fn [inverted [node dependencies]]
             (for [dep dependencies]
               (if (contains? inverted dep)
                 (let [required-by (get inverted dep)]
                   (assoc inverted dep (conj required-by node)))
                 (assoc inverted dep #{node})))) graph)
Is there an elegant solution to this?

moe09:01:49

(reduce-kv
 (fn [acc par deps]
   (reduce #(update %1 %2 (fnil conj #{}) par) acc deps))
 {}
 graph)

moe09:01:53

(fixed a typo)

Patrick Winter11:01:07

This looks a lot cleaner 🙂. Thanks @U04HK53G7SQ

moe11:01:47

No worries!

popeye11:01:30

(def x {:foo 1, :bar -3}) (def y {:foo 1, :bar -3})   (identical? x y) returns false

(def a 1)
(def b 1)

Why (identical? a b) - returns true ?

moe11:01:19

Because the maps are not identical objects in memory. Check out https://clojuredocs.org/clojure.core/identical_q and read the comments, especially the last one about being careful about using the function at all

moe11:01:22

It's JVM semantics, you can come up with much simpler cases, like (identical? 0.0 .0.0) => false

moe11:01:17

It's best considered a useless function

popeye12:01:31

Oh ok Thanks you

popeye14:01:41

I have seen code in the clojure core that make use with-meta when do we need to use with-meta in our application ?

delaguardo14:01:55

when you have to add metadata to some dynamically created object that supports metadata.

user=> (meta (let [x [1 2 3]] ^:foo x))
nil
user=> (meta (let [x [1 2 3]] (with-meta x {:foo true})))
{:foo true}
the first line here might look like you add metadata to the object but in fact it adds metadata to the var #'x that doe not exists outside of let expression

popeye14:01:58

Why do we have to add metadata ?

popeye14:01:53

I meant, which scenario we add it? is there any drawback if we do not add it ?

delaguardo14:01:21

there are few cases when it can be usefull here is one for example https://clojure.org/reference/protocols#_extend_via_metadata

delaguardo14:01:08

by adding metadata you can implement a protocol implicitly

popeye14:01:41

Will take a look

simongray15:01:22

Metadata is also useful for cases where you want to be able to compare data using = while attaching certain metadata to the data, e.g. :source . The data stays equivalent, but you get to keep track of where it came from.

simongray15:01:06

This returns true, for example:

(= (with-meta {:a 1} {:source "$some_user"})
   (with-meta {:a 1} {:source "$some_other_user"}))

jcb15:01:44

Can I ask for some advice please, as I've hit a brick wall in my understanding? I'm sure this has been asked before but I can't find an answer that I fully understand. I have an array of maps that is originally derived from a json file. I'm trying to perform a substring search on one of the keys in each map and create a new array of maps with all the full map entries that return true. e.g [{:title "the quick brown fox" :data "data" :more "data"} {:title "the slow brown fox" :data "data2" :more "data2"} ] (into [] (filter (string/includes? (:title map) "quick") data) would return [{:title "the quick brown fox" :data "data" :more "data"}] However, after a mixed bag of various attempts at using filter I either get empty arrays, arrays with true or false values or errors. Are there any useful links or documentation that might point me in the right direction? Thanks!

moe15:01:43

I'm not sure if it's a typo or part of your problem, but you're not passing a function to filter, you're passing the boolean result of calling a function

moe16:01:58

vs. say (filter (fn [{title :title}] (str/includes? title "quick")) data)

jcb16:01:00

Yes, sorry it's become peudo code at this point after a few goes around,🙃

R.A. Porter16:01:43

If you care about the result being a vector and not a lazy seq, you could call

(let [foo [{:title "the quick brown fox"
            :data  "data"
            :more  "data"}
           {:title "the slow brown fox"
            :data  "data2"
            :more  "data2"}]]
  (filterv #(str/includes? (:title %) "quick") foo))
Just filter would return a lazy seq.

moe16:01:52

that code is testing the maps for string inclusion

R.A. Porter16:01:20

Edited. I’d elided the extraction of the :title.

moe16:01:28

@U2EJEK2SX if you want to paste a gist or something I can try to help

dpsutton16:01:59

A way to think about this so you can get yourself unstuck in the future. When you want to do something to a collection, write a function that works on a single one. And only once that function is working on a single one then use it with filter and the rest of the functions

☝️ 4
🙂 2
jcb16:01:30

Thanks everyone, I got into the weeds with trying to parse every map etc

kennytilton16:01:33

Meta-tip: I know well the temptation, but I try never to post anything other than actual code. People are going to spend time on analyzing and even running it, I figure, so it has to be real. No harm I guess in loudly announcing the code is just pseudo-code up front. hth!

jcb16:01:34

Sorry! I'll keep that in mind in the future

🙏 2
skylize18:01:12

Demonstration of @U11BV7MTK’s suggestion. Break it down to extremely easy problems, and build back up to the target.

👍 3
2
jcb14:01:25

Thanks @U90R0EPHA that's a really helpful example

Stuart18:01:33

I could do with some help, I have the following data structure

(let [c {1 [1 2 3 4 5]
         2 [1 2 3 4 5]
         3 [6 7 8 9 10]
         4 [1 4 5 6 7]}]
And values a and b. What I'd like to do is remove all keys from c that are less than a , and when the key is equal to a, remove all values from that key which are less than b. e.g.
(let [c {1 [1 2 3 4 5]
         2 [1 2 3 4 5]
         3 [6 7 8 9 10]
         4 [1 4 5 6 7]}
      a 3
      b 7]
Would give
{3 [7 8 9 10]
 4 [1 4 5 6 7]}
What I've tried to get working:
(-> (into {} (remove (fn [[k _]] (< k a)) c))
    (assoc a (remove (fn [[_ v]] (< v b))(c a))))
But I'm getting the error ; TypeError: n.replace is not a function and no idea why!

Stuart18:01:59

This works, but I'm thinking there must be a nicer way

(into {} (for [[k v] c
                 :when (>= k a)]
             [k (if (= k a)
                  (remove (fn [x] (< x b)) v) v)]))

Stuart18:01:10

I hadn't! Would that make removing keys less than n simpler ?

moe18:01:25

`(subseq (into (sorted-map) {1 [1 2 3 4 5] 2 [1 2 3 4 5] 3 [6 7 8 9 10] 4 [1 4 5 6 7]}) < n)`

Stuart18:01:27

nice, i didnt' know about subseq either

dpsutton18:01:12

❯ clj -Sdeps '{:deps {org.clojure/data.avl {:mvn/version "0.1.0"}}}'
Downloading: org/clojure/data.avl/0.1.0/data.avl-0.1.0.pom from central
Downloading: org/clojure/data.avl/0.1.0/data.avl-0.1.0.jar from central
Clojure 1.11.1
user=> (require '[clojure.data.avl :as avl])
nil
user=>   (let [c (avl/sorted-map
            1 [1 2 3 4 5]
            2 [1 2 3 4 5]
            3 [6 7 8 9 10]
            4 [1 4 5 6 7])
        a 3
        b 7]
    (avl/subrange c >= a <= b))
{3 [6 7 8 9 10], 4 [1 4 5 6 7]}
user=>

Stuart18:01:26

Is their any specific reason why I was getting the error n.replace is not a function with my code ? I'm finding clojure(script) errors pretty tricky to deal with and find the actual problem

moe18:01:24

for the rest i'd go w/ something like (as-> thing m (into (sorted-map) m) (update m a (partial filter (partial >= b)) (subseq m < n) (into {} m)) or whatever

dpsutton18:01:39

avl trees offer a non-linear way to accomplish this. just wanted to highlight that. ie no filter on the keys yourself

👍 2
Stuart18:01:05

I'll check it out, wasn't aware of that library

moe19:01:09

on the error, you're trying to destructure members of (c a) into [_ v], but it's a flat vector

Stuart19:01:32

oh yeah! I was confused thinking I was still dealing with key value pairs at that point.

moe19:01:42

obviously the error message is of no help

tschady23:01:46

I don’t think it’s great, but an option is reduce-kv with a cond in the body

Michał Frątczak20:01:35

How is it possible this works? pluss function arity is 2

(defn pluss [x y]
    (Integer/sum x y))
  
  (reduce pluss [1]) => 1
  

Alex Miller (Clojure team)20:01:59

"If coll has only 1 item, it is returned and f is not called."