13

是否有一种惯用的方法来确定 LazySeq 是否包含元素?从 Clojure 1.5 开始,调用contains?会引发 IllegalArgumentException:

IllegalArgumentException contains? not supported on type: clojure.lang.LazySeq      
clojure.lang.RT.contains (RT.java:724)

据我所知,在 1.5 之前,它总是返回 false。

我知道调用contains?LazySeq 可能永远不会返回,因为它可能是无限的。但是如果我知道它不是并且不在乎它是否被热切地评估呢?

我想出的是:

(defn lazy-contains? [col key]
  (not (empty? (filter #(= key %) col))))

但感觉不太对劲。有没有更好的办法?

4

2 回答 2

16

首先,惰性序列对于检查成员资格无效。考虑使用集合而不是惰性序列。

如果一组不切实际,那么您的解决方案也不错。一些可能的改进:

  1. “不为空”有点尴尬。仅使用 seq 就足以获得用户可以在 if 中使用的 nil-or-truthy 值。如果需要 true 或 false,可以将其包装为布尔值。

  2. 由于您只关心第一个匹配项,因此您可以使用 some 而不是 filter 和 seq。

  3. 编写相等谓词的一种方便方法是使用文字集,例如#{key},尽管如果 key 为 nil,无论是否找到 nil,它都将始终返回 nil。

所有这些都为您提供:

(defn lazy-contains? [col key]
  (some #{key} col))
于 2013-04-28T17:04:08.083 回答
5

如果您使用some而不是filter在您的示例中使用,您将在找到值后立即获得返回,而不是强制评估整个序列。

(defn lazy-contains? [coll key]
  (boolean (some #(= % key) coll)))

编辑:如果您不将结果强制为布尔值,请注意,如果找不到密钥,您将得到nil而不是。false

于 2013-04-28T16:33:39.657 回答