Thank you for your feedback and interesting ideas. I've decided to bite the bullet and to write my own multi-filter fn. I'm very new to Clojure so any (constructive :-) ) criticism is welcome:
(defn multi-filter [filters coll] (reduce (fn [res e] (map (fn [f r] (if (f e) (conj r e) r)) filters res)) (repeat (count filters) []) coll ) ) It takes a list of filter functions and coll and returns a list of vectors each one containing result of corresponding filter. Here is how I use it in my context: (let [ ... [sales upgrades demo] (multi-filter [ #($ % "Product Type Identifier" = "1" && % "Vendor Identifier" = "01010012" ) #($ % "Product Type Identifier" = "7" && % "Vendor Identifier" = "01010012" ) #($ % "Product Type Identifier" = "1" && % "Vendor Identifier" = "01010318" ) ] (get-idata) ) ] Evaluation happens during destructuring bind (which is good for me because idata is coming from file). Interestingly enough replacing map with eager-map in multi-filter definition gives very insignificant boost in perf (less than 10%), so I've decided to leave it as is. May be there are improvements possible to my emap definition? (defn emap [f c1 c2] (loop [s1 (seq c1) s2 (seq c2) res [] ] (if (and s1 s2) (recur (seq (rest s1)) (seq (rest s2)) (conj res (f (first s1) (first s2)))) res))) - Dmitry On Oct 19, 12:13 pm, Meikel Brandmeyer <m...@kotka.de> wrote: > Hi, > > Am 19.10.2009 um 01:34 schrieb Dmitry Kakurin: > > > This is in line with what I was thinking for my own custom filter > > function. > > Now how would you modify it if the same record can be both "sales" and > > "upgrade" at the same time? > > I.e. if filters are not mutually exclusive. > > I'd define a helper. (Code untested) > > (defmacro ->if > "Acts like ->, but pipes the expression only through the next step > if the predicate clause returns true. Otherwise it skips the step > going on with the next steps, if any." > ([x] x) > ([x pred form & forms] > (let [x-gs (gensym "x")] > `(let [~x-gs ~x] > (if (-> ~x-gs ~pred) > (-> ~x-gs form (->if ~...@forms)) > (->if ~x-gs ~...@forms)))))) > > (letfn [(add-sale > [[sales upgrades demos] x] > [(conj sales x) upgrades demos]) > (add-upgrade > [[sales upgrades demos] x] > [sales (conj upgrades x) demos]) > (add-demo > [[sales upgrades demos] x] > [sales upgrades (conj demos x)])] > (reduce (fn [sales-upgrades-demos data] > (->if sales-ugprades-demos > (do (is-sales? data)) (add-sale data) > (do (is-upgrade? data)) (add-upgrade data) > (do (is-demo? data)) (add-demo data))) > [[] [] []] (get-idata))) > > This is maybe trying to be a little too clever, but well... I found > something like ->if useful at times. Note that, the predicate there > normally depends on the thing piped through the chain with ->. However > in our case it is not. That's what's the do is for: to ignore the > argument of the ->. > > Looking at this, I would think, that the other approaches using the > group are much more elegant. > > Hmm.. Another approach might be juxt: > > (defn conj-if > "Conjoins x to coll if x fulfills pred." > [pred coll x] > (if (pred x) > (conj coll x) > coll)) > > (reduce (juxt #(conj-if is-sales? (nth %1 0) %2) > #(conj-if is-upgrade? (nth %1 1) %2) > #(conj-if is-demo? (nth %1 2) %2)) > [[] [] []] (get-idata)) > > This looks much nicer, although there is still the ugly nth > "destructuring" for vector. And juxt is maybe only semi-official API > at the moment... If you don't want to depend on contrib, this might be > an alternative, though... > > Sincerely > Meikel > > smime.p7s > 3KViewDownload --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---