【问题标题】:Clojure: Idiomatic way to call contains? on a lazy sequenceClojure:调用包含的惯用方式?在惰性序列上
【发布时间】:2013-04-22 07:15:54
【问题描述】:

是否有确定 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。

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

我想出的是:

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

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

【问题讨论】:

    标签: clojure lazy-sequences


    【解决方案1】:

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

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

    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))
    

    【讨论】:

    • 以 nil 作为键的情况使它有些不正确。但因为在我的情况下,关键永远不会为零,我可以忍受它。
    • 对。要解决这个问题,只需使用您的原始谓词:(some #(= key %) col)
    • @Chouser 我一直在尝试将这些替代方案中的任何一种用于特定用途,并且遇到了以下问题。我怎样才能让这个更接近原始包含?功能? (lazy-contains? {:state "active", :course_n "law", :course_i "C0"} :state) 返回 nil 但使用 contains 时?它返回 true 我也在尝试通过 clojuredocs 进行探索,但没有看到如何修复它。
    【解决方案2】:

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

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

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

    【讨论】:

    • 像我一样使用过滤器不会评估整个序列,只要首先找到值。 (lazy-contains? (range) 100) 返回真。那不就相当于你的功能了吗?
    猜你喜欢
    • 1970-01-01
    • 2013-11-28
    • 2023-03-21
    • 2013-08-06
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    • 2014-06-17
    相关资源
    最近更新 更多