Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure equivalent to Python's "any" and "all" functions?

Tags:

python

clojure

Are there built in functions in Clojure similar to Python's any and all functions?

For example, in Python, it's all([True, 1, 'non-empty string']) == True.

like image 895
TorelTwiddler Avatar asked Oct 24 '11 04:10

TorelTwiddler


2 Answers

(every? f data) [docs] is the same as all(f(x) for x in data).

(some f data) [docs] is like any(f(x) for x in data) except that it returns the value of f(x) (which must be truthy), instead of just true.

If you want the exact same behaviour as in Python, you can use the identity function, which will just return its argument (equivalent to (fn [x] x)).

user=> (every? identity [1, true, "non-empty string"])
true
user=> (some identity [1, true "non-empty string"])
1
user=> (some true? [1, true "non-empty string"])
true
like image 97
Jeremy Avatar answered Sep 21 '22 05:09

Jeremy


In clojure and and or are quite similar to python's all and any, with the caveat that (just like clojure.core/some) they return the element that will satifsy it... thus you can use it together with boolean to convert it

(boolean (or "" nil false)) ; "" is truthy in clojure
; => true
(boolean (and [] "" {} () 0)) ; also [], {}, () and 0 are truthy
; => true

I use boolean instead of true? since the latter will return true iff the argument is the value true... so boolean is more akin to python's bool in that it evaluates the truthyness

Unlike some & every?, and & or are macros, so if you always want to convert the result to a boolean, you cannot simply do (def any (comp boolean or)) but you have to define a macro like

(defmacro any [& v] `(boolean (or ~@v)))
(defmacro all [& v] `(boolean (and ~@v)))

a side-effect/advantage of being macros, is that they are lazy/can shortcircuit (just like python's and & or, that are infix binary operators however)

(any "" (/ 1 0))
; => true
(all nil (/ 1 0))
; => false

and they're just like python's any and all, even when called without arguments

(any)
; => false
(all)
; => true

in python:

>>> any([])
False    
>>> all([])
True

If you prefer to have to call any/all with a single list/sequence argument, you can simply do:

(defmacro all [v] `(boolean (and ~@v)))

(all [])
; => true
(all [nil (/ 1 0)])    
; => false
like image 25
berdario Avatar answered Sep 23 '22 05:09

berdario