Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure thread-first with filter function

I'm having a problem stringing some forms together to do some ETL on a result set from a korma function.

I get back from korma sql:

({:id 1 :some_field "asd" :children [{:a 1 :b 2 :c 3} {:a 1 :b 3 :c 4} {:a 2 :b 2 :c 3}] :another_field "qwe"})

I'm looking to filter this result set by getting the "children" where the :a keyword is 1.

My attempt:

;mock of korma result
(def data '({:id 1 :some_field "asd" :children [{:a 1 :b 2 :c 3} {:a 1 :b 3 :c 4} {:a 2 :b 2 :c 3}] :another_field "qwe"}))

(-> data 
    first 
    :children 
    (filter #(= (% :a) 1)))

What I'm expecting here is a vector of hashmaps that :a is set to 1, i.e :

[{:a 1 :b 2 :c 3} {:a 1 :b 3 :c 4}]

However, I'm getting the following error:

IllegalArgumentException Don't know how to create ISeq from: xxx.core$eval3145$fn__3146  clojure.lang.RT.seqFrom (RT.java:505)

From the error I gather it's trying to create a sequence from a function...though just not able to connect the dots as to why.

Further, if I separate the filter function entirely by doing the following:

(let [children (-> data first :children)] 
    (filter #(= (% :a) 1) children))

it works. I'm not sure why the first-thread is not applying the filter function, passing in the :children vector as the coll argument.

Any and all help much appreciated.

Thanks

like image 305
OnResolve Avatar asked Dec 24 '22 18:12

OnResolve


1 Answers

You want the thread-last macro:

(->> data first :children (filter #(= (% :a) 1)))

yields

({:a 1, :b 2, :c 3} {:a 1, :b 3, :c 4})

The thread-first macro in your original code is equivalent to writing:

(filter (:children (first data)) #(= (% :a) 1))

Which results in an error, because your anonymous function is not a sequence.

like image 122
Diego Basch Avatar answered Dec 28 '22 10:12

Diego Basch