Fork me on GitHub
#beginners
<
2023-12-22
>
leifericf12:12:50

I'm trying to filter a map based on two values (by key-lookup). This does not work as intended, but perhaps it illustrates what I'm trying to accomplish and what I'm doing wrong:

(filter #(and (= "python-test-env" (:projectName %))
              (= "dev" (:stackName %)))) 
coll (the list of maps) is piped into filter with ->> I have a list of maps, each map containing several key-vals:
({:orgName "my-org",
  :projectName "my-project",
  :stackName "stack-1,
  :lastUpdate 1695305272,
  :resourceCount 14}
 {:orgName "my-org",
  :projectName "my-project",
  :stackName "stack-2",
  :lastUpdate 1695106891,
  :resourceCount 16}
 {:orgName "my-org",
  :projectName "my-project",
  :stackName "stack-3",
  :lastUpdate 1698324490,
  :resourceCount 16}
 ...)
And I want to get only those maps where the criteria match. How can I do that?

delaguardo12:12:35

(filter #(= ["dev" "python-test-env"] ((juxt :stackName :projectName) %)))

leifericf12:12:16

Wow, nice! Thanks. Here's a working code sample in case anyone else finds it useful:

(let [data (list {:orgName "my-org"
                  :projectName "my-project"
                  :stackName "stack-1"
                  :lastUpdate 1695305272
                  :resourceCount 14}
                 {:orgName "my-org"
                  :projectName "python-test-env"
                  :stackName "dev"
                  :lastUpdate 1695106891
                  :resourceCount 16}
                 {:orgName "my-org"
                  :projectName "my-project"
                  :stackName "stack-3"
                  :lastUpdate 1698324490
                  :resourceCount 16})]
  (->> data
       (filter #(= ["dev" "python-test-env"]
                   ((juxt :stackName :projectName) %)))))

leifericf12:12:24

Although I have no idea how juxt works 😅

delaguardo12:12:44

however, your snippet should work just fine. My example does not do anything different

wow 1
delaguardo12:12:33

Just a nice way to say that ((juxt a b c) x) => [(a x) (b x) (c x)]

💡 2
leifericf12:12:41

Ah, wow! Yes, it does work with my test data! But not with the data returned from the API I'm using. Weird.

leifericf12:12:58

Maybe I don't have a list of maps after all, from the API I'm consuming. Hmmm.

delaguardo12:12:37

maybe keys a not keywords? some clients doesn't translate keys automaticaly from strings

leifericf12:12:51

I'm converting it to keywords like so:

(defn response-body->json [response]
  (-> (:body response)
      (json/parse-string keyword)))

(defn make-request [request]
  (-> request
      (http-kit/request response-body->json)
      deref))

(defn fetch-page [request & [token]]
  (-> request
      (cond-> token (assoc-in [:query-params :continuationToken] token))
      make-request))

(defn fetch-all-pages [request val-fn key-fn]
  (-> (iteration (partial fetch-page request)
                 :vf val-fn
                 :kf key-fn)
      seq
      flatten))
Using (json/parse-string keyword) in response-body->json

delaguardo12:12:46

and parse-string is from cheshire?

1
leifericf12:12:20

And here is my whole ->> thread:

(doall
   (->> (fetch-all-pages stack-request :stacks :continuationToken)
        (filter #(and (= "python-test-env" (:projectName %))
                      (= "dev" (:stackName %))))
        (create-permission-request "PULUMI_ALL_STACKS_READ" :read)
        make-request))

delaguardo12:12:36

(doall
   (->> (fetch-all-pages stack-request :stacks :continuationToken)
        (filter #(and (= "python-test-env" (:projectName %))
                      (= "dev" (:stackName %))))
        (create-permission-request "PULUMI_ALL_STACKS_READ" :read)
        make-request))
you missed filter call. probably just a typo

leifericf12:12:05

Ah, sorry, that was actually a copy-paste error from when I tried your juxt solution and reverted back to mine. I edited my thread above again now.

leifericf12:12:47

I found out that (fetch-all-pages stack-request :stacks :continuationToken) returns a clojure.lang.LazySeq (not a list of maps) which is passed on to filter.

delaguardo12:12:25

that is fine. filter can filter lazy seqs

👍 1
delaguardo12:12:35

I would start step by step debugging but usually this depends on IDE support. another way could be this:

(filter (fn [x]
          (prn "---DBG" x)
          (= ["dev" "python-test-env"] ((juxt :stackName :projectName) x))))

💡 1
delaguardo12:12:09

just print every item that is passed to the filter to see unexpected data structure

leifericf12:12:43

Awesome, thanks for the help!

leifericf12:12:13

Oh my Lord, I'm such a dumbass. python-test-repo was the actual project name. I just filtered for the wrong string 😅:man-facepalming:

leifericf12:12:58

And my code was correct, haha! Sorry for wasting your time, @U04V4KLKC

leifericf12:12:15

Although that debug trick of yours did help me realize my mistake!

delaguardo13:12:38

no worries, glad to help)

💜 1
jwind13:12:13

Hey all, I get this error when trying to build the uberjar, where do I look for the files to add to exclusions?

Execution error (ExceptionInfo) at clojure.tools.build.tasks.uber/explode (uber.clj:172).
Cannot write META-INF/license/LICENSE.aix-netbsd.txt from io.grpc/grpc-netty-shaded as parent dir is a file from another lib. One of them must be excluded.

Full report at:
/var/folders/mr/vq80v4cn4rgdtl1pbfrcfvvr0000gp/T/clojure-5285222528425535868.edn

seancorfield15:12:58

I searched Slack for exclude license

jwind19:12:50

Thank you!

James Amberger15:12:33

What happens if you add-watch and reuse the keyword?

Bob B15:12:45

it looks like the watches are added to a map, and add-watch calls assoc , so the old watch is replaced

James Amberger15:12:35

hm. so if you are creating watches programmatically, what should you do about a key? just grab something from your context that would be unique?

Bob B15:12:44

sure - gensyms are also an option

James Amberger22:12:31

Why is (seq? [1 2 3]) false?

Bob B22:12:01

The sort of glib answer is that a vector doesn't implement ISeq. If the desired is a function that can identify if its argument can be converted to a sequence with the seq function, that's seqable?

Alex Miller (Clojure team)22:12:00

vectors are not seqs, but can provide a seq view

Alex Miller (Clojure team)22:12:17

seq functions seq their argument to obtain the view

James Amberger23:12:14

Thank you. This raises more questions but I will try to divine the answers myself first.