Clojure中相当于Python的“any”和“all”函数的方法是什么?

30

Clojure中是否有类似于Python的anyall函数的内置函数?

例如,在Python中,all([True, 1, 'non-empty string']) == True

2个回答

43

(every? f data) [文档] 的作用与all(f(x) for x in data)相同。

(some f data) [文档] 类似于Python中的any(f(x) for x in data),但它会返回f(x)的值(必须是真值),而不仅仅是true

如果您想要与 Python 完全相同的行为,可以使用 identity 函数,该函数将只返回其参数(等效于 (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

3
我认为使用 identity 函数而不是新的匿名函数会更好。例如,(every? identity [1, true, "non-empty-string"]),(some identity [1, true, "non-empty-string"])... - Verneri Åberg
+1 给 Verneri 的评论,关于使用 identity。这更符合惯用语。 - Gert
1
这并不是人们所期望的。 (some f data) 返回的既不是 true 也不是 false,而是像 Jeremy 所说的,Clojure 认为是 true 的 f(x) 的第一个值,而不是 true 符号。 另一方面,如果没有任何 x 的 f(x) 评估为 true,则 (some) 返回 nil,而不是 false 符号。 为了像 every? 一样运行,需要进行进一步处理,例如 (true? (some f data))。 PS:(some true? data) 仍然无法工作,因为对于没有匹配项它返回 nil。 - Alex
另外,(some true? data) 不是你从 Python 中期望的 any(some true? [1 [true] "non-empty-string"]) 会产生一个假值。 - berdario

3
在Clojure中,andor与Python的allany非常相似,但(就像clojure.core/some一样)它们返回满足条件的元素...因此您可以将其与boolean一起使用来进行转换。
(boolean (or "" nil false)) ; "" is truthy in clojure
; => true
(boolean (and [] "" {} () 0)) ; also [], {}, () and 0 are truthy
; => true

我使用boolean代替true?,因为后者只有当参数是true时才返回true...所以boolean更类似于python中的bool,它评估真值。

someevery?不同,andor是宏,所以如果你总是想将结果转换为布尔值,就不能简单地执行(def any (comp boolean or)),而是必须定义一个宏,比如:

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

作为宏的副作用/优势之一就是它们是懒惰的/可以短路(就像 Python 的 andor 一样,它们是中缀二元运算符)。
(any "" (/ 1 0))
; => true
(all nil (/ 1 0))
; => false

它们与Python的anyall非常相似,即使在没有参数的情况下调用也是如此。

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

在Python中:

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

如果您希望使用单个列表/序列参数来调用any/all,您可以这样做:
(defmacro all [v] `(boolean (and ~@v)))

(all [])
; => true
(all [nil (/ 1 0)])    
; => false

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接