How would you combine sorting and filter in Clojure?

Let's say I have a set of strings, and I want to return all strings longer than 4 characters, first sorted by shortest string.

You can solve this with something like:

(def strings ["this" "is" "super" "cool" "everybody" "isn't" "clojure" "great!?!?"]) (sort-by count < (filter #(> (count %) 4) strings)) ;; > ("super" "isn't" "clojure" "everybody" "great!?!?") 

Note that we use count twice. This is probably good, but what if count not count ? What if, instead of count we call super-expensive-function , that we really won’t run more than is absolutely necessary?

So:

  • We have a collection of things
  • We want to return an ordered collection of things
  • Filtered and sorted using a computationally expensive function that should only be called once per piece

Is there an existing function that does this, or do I need to create my own?

+4
source share
3 answers

The simplest solution would be to combine each element together with its expensive computational property, then filter and sort, and then discard the parameter:

 (->> strings (map (juxt identity count)) (filter (fn [[_ c]] (> c 4))) (sort-by peek) (map first)) 

If the calculation of the property in question is really expensive, the overhead of vector extraction should almost disappear.

+8
source

Maybe the JIT compiler can understand that this expensive intermediate result can be cached between two operations? It is worth trying to manage this feature, given the increased complexity in manually caching the result. I would run a performance test several times for various timed solutions as follows:

 (time (dotimes [_ 1e5] ...)) 
+1
source

You can connect to a group using grouping, and perform aggregation and filtering with a list.

 (for [[c sv] (sort-by first (group-by count strings)) :when (> c 4) s sv] s) 
0
source

Source: https://habr.com/ru/post/1496716/


All Articles