I have a sequence of map-pairs like this (currently about 17000 pairs)
(def myseq '({:name "Peter" :rank 2222} {:name "Anna" :rank 111}))
I want to filter specific pairs into a new sequence with
(filter (fn [x] (> x 222)) (:rank (first myseq)))
I have been trying to iterate with loop like this but keep getting thread-death. Also if I use filter on a a single map collection it just returns a new sequence, not sure if I need to create one myself here?
(defn remove-lower [number myseq]
(loop [i 0]
(if (= i (count file))
(println "done")
(filter [x] (> x number))
(:rank (first myseq))))
(recur (rest myseq))))
Finally is looping the most efficient way to get the new sequence of pairs?
No need for loop/recur here. filter already iterates through a seq for you:
(filter (fn [entry] (> (:rank entry) 220)) myseq)
First thing to know is that (most of) the data structures in clojure are immutable and most functions are, well, functional. That means, that they don't have side effects. In your case filter
doesn't change the sequence in any way, it returns a new one, containing only the unfiltered items.
So, to filter myseq
you need to do something like:
(def filtered-seq (filter (fn [x] ...) myseq))
Filter will call the function repeatedly, binding x
to the currently filtered item in myseq
. That is, the first time it'll be bound to {:name "Peter" :rank 2222}
, then to {:name "Anna" :rank 111}
. The filtered-seq
will contain only the elements, for which the function returned true. myseq
will not be modified!
So, you want to leave only elements with :rank
higher than 222:
(filter (fn [x] (> (:rank x) 222)) myseq)
That's it. And one more thing about filter is, that it's lazy. That is, items in the returned collection are "realized" (or computed) only when they are needed.
You don't need to use loop
for this, as filter
does the job nicely, and loop
isn't lazy.
That said, your loop
doesn't work because it has several problems:
recur
is outside the loop
. In this case clojure will loop back to the beginning of the function.The code could look something like this (untested):
(defn remove-lower [number myseq]
(loop [sq myseq res []]
(if (empty? sq)
res
(let [current (first sq)]
(if (> (:rank current) number)
(recur (rest sq) (conj res current))
(recur (rest sq) res))))))
Note how:
recur
is now inside the loop
res
contains the return value and sq
contains the currently left sequencerecur
passes the new values of sq
and res
for the next iterationsq
is "shrinked" with each iteration, so the loop will eventually exit unless myseq
is infinite. Contrast this to filter
, which handles infinite sequences just fine.As you see this is harder to read and less general than filter
and also is eager (not lazy).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With