I want to apply a series of tests on my list and make sure that all the tests are passed. Is there a function similar to "andmap" in Clojure?
You could use every?
:
user=> (every? string? '("hi" 1))
false
Here's the documentation on every?
.
Clojure 1.3 will add every-pred (and the related some-fn for the "or" version).
clojure.core/every-pred ([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps])
Takes a set of predicates and returns a function f that returns true if all of its composing predicates return a logical true value against all of its arguments, else it returns false. Note that f is short-circuiting in that it will stop execution on the first argument that triggers a logical false result against the original predicates.
A naive implementation might be:
(defn every-pred [& preds] (fn [& args] (every? #(every? % args) preds)))
but the actual implementation will have better performance.
I wrote andmap
as a macro which takes predicates as its arguments and builds a function that "wraps an and
around the predicates", i.e.,
(andmap integer? odd?)
==>
(fn [x] (and (integer? x)
(odd? x)))
(it doesn't expand to exactly this, but it expands to something equivalent to this)
This has the advantage that it shortcuircuts on the predicates so you can write
(every? (andmap integer? odd?) [1 3 "a string"])
without getting a runtime exception as you would get with Arthurs answer.
Here is the definition of andmap
:
(defmacro andmap ([] `(fn [& x#] true)) ([p & ps] `(fn [& x#] (and (apply ~p x#) (apply (andmap ~@ps) x#)))))
It is also possible to define andmap
as an function which also short-circuits on it's predicates due to lazyness:
(defn andmap [& ps] (fn [& x] (every? true? (map (fn [p] (apply p x)) ps))))
The predicates to andmap can take an arbitrary number of arguments, so it is possible to write
(map (andmap #(and (integer? %1)
(integer? %2))
#(and (odd? %1)
(even? %2))
<)
[1 3 9]
[2 6 "string"])
which evaluates to (true true false)
.
every?
will ask "Does this one function return true for each member of the seq", which is close to what I think you are asking for. An improvement on every?
would take a list of functions and ask "Are all these predicates true for every member of this seq".
Here is a first attempt:
(defn andmap? [data tests]
(every? true? (for [d data, f tests]
(f d))))
user> (andmap? '(2 4 8) [even? pos?])
true
user> (andmap? '(2 4 8) [even? odd?])
false
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