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 <[email protected]> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---