Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Data structures 测试列表是否包含Clojure中的特定值_Data Structures_Clojure - Fatal编程技术网

Data structures 测试列表是否包含Clojure中的特定值

Data structures 测试列表是否包含Clojure中的特定值,data-structures,clojure,Data Structures,Clojure,在Clojure中测试列表是否包含给定值的最佳方法是什么 特别是,包含?的行为目前让我感到困惑: (contains? '(100 101 102) 101) => false 很明显,我可以编写一个简单的函数来遍历列表并测试是否相等,但肯定有一种标准的方法可以做到这一点?啊,包含?。。。应该是五大常见问题之一:Clojure 它不检查集合是否包含值;它检查是否可以使用get检索项,或者换句话说,集合是否包含键。这对于集合(可以认为不区分键和值)、映射(因此(包含?{:foo 1}:fo

在Clojure中测试列表是否包含给定值的最佳方法是什么

特别是,
包含?
的行为目前让我感到困惑:

(contains? '(100 101 102) 101) => false

很明显,我可以编写一个简单的函数来遍历列表并测试是否相等,但肯定有一种标准的方法可以做到这一点?

啊,
包含?
。。。应该是五大常见问题之一:Clojure

它不检查集合是否包含值;它检查是否可以使用
get
检索项,或者换句话说,集合是否包含键。这对于集合(可以认为不区分键和值)、映射(因此
(包含?{:foo 1}:foo)
true
)和向量(但是请注意
(包含?[:foo:bar]0)
true
,因为这里的键是索引,而所讨论的向量确实“包含”索引
0
!)

如果调用
contains?
没有意义,只需返回
false
;这是在
(contains?:foo 1)
(contains?)(100 101 102)101)
中发生的情况。更新:在Clojure≥ 1.5
包含?
当递给不支持预期“密钥成员资格”测试类型的对象时抛出

正确的方法如下所示:

; most of the time this works
(some #{101} '(100 101 102))
(some #{:b} [:a :b :c]) ; = :b, which is truthy
在搜索一组项目中的一个时,可以使用更大的集合;在搜索
false
/
nil
时,可以使用
false?
/
nil?
——因为
({x}x)
返回
x
,因此
({nil}nil)
nil
;当搜索多个项目中的一个时,其中一些可能是
false
nil
,您可以使用

(some (zipmap [...the items...] (repeat true)) the-collection)

(请注意,在任何类型的集合中,项目都可以传递到
zipmap

我使用的标准实用程序中有一个快速功能:

(defn seq-contains?
  "Determine whether a sequence contains a given item"
  [sequence item]
  (if (empty? sequence)
    false
    (reduce #(or %1 %2) (map #(= %1 item) sequence))))

值得一提的是,这是我对列表包含函数的简单实现:

(defn list-contains? [coll value]
  (let [s (seq coll)]
    (if s
      (if (= (first s) value) true (recur (rest s) value))
      false)))

以下是我的标准util,用于相同的目的:

(defn in? 
  "true if coll contains elm"
  [coll elm]  
  (some #(= elm %) coll))

我是建立在j-g-faustus的“列表包含?”。它现在接受任意数量的参数

(defn list-contains?
([collection value]
    (let [sequence (seq collection)]
        (if sequence (some #(= value %) sequence))))
([collection value & next]
    (if (list-contains? collection value) (apply list-contains? collection next))))

我知道我有点晚了,但是:

(contains? (set '(101 102 103)) 102)
最后在clojure 1.4中输出true:)

工作正常,但以下更好:

(some #(= 102 %) '(101 102 103)) 

推荐的方法是将
some
与集合一起使用-请参阅
clojure.core/some
的文档

然后,您可以在真/假谓词中使用
some
,例如

(defn in? [coll x] (if (some #{x} coll) true false))

如果您有一个向量或列表,并且希望检查其中是否包含值,您将发现这不起作用。 米夏已经有了

在这种情况下,您可以尝试以下四种方法:

  • 考虑您是否真的需要一个向量或列表。如果您使用集合,
    包含?
    将起作用

    (contains? #{:a :b :c} :b) ; = true
    
  • 使用,将目标包装成一组,如下所示:

    ; most of the time this works
    (some #{101} '(100 101 102))
    
    (some #{:b} [:a :b :c]) ; = :b, which is truthy
    
  • 如果正在搜索错误值(
    false
    nil
    ),则设置为函数快捷方式将不起作用

    在这些情况下,应对该值使用内置谓词函数,或:

  • 如果您需要经常进行此类搜索,请为其编写一个函数

    (defn seq-contains? [coll target] (some #(= target %) coll))
    (seq-contains? [true false true] false) ; = true
    

  • 此外,请参阅以了解检查序列中是否包含多个目标中的任何一个的方法。

    以下是经典的Lisp解决方案:

    (defn member? [list elt]
        "True if list contains at least one instance of elt"
        (cond 
            (empty? list) false
            (= (first list) elt) true
            true (recur (rest list) elt)))
    
    (defn member?
      "I'm still amazed that Clojure does not provide a simple member function.
       Returns true if `item` is a member of `series`, else nil."
      [item series]
      (and (some #(= item %) series) true))
    

    它就像使用一个集合一样简单-类似于映射,您可以将它放在函数位置。如果在集合中(这是真的)或
    nil
    (这是假的),则其计算值为:

    如果您正在检查运行时之前无法获得的大小合理的向量/列表,您还可以使用
    set
    功能:

    ; (def nums '(100 101 102))
    ((set nums) 101) ; 101
    

    您始终可以使用.methodName语法调用java方法

    (.contains [100 101 102] 101) => true
    

    由于Clojure是基于Java构建的,因此您可以轻松地调用
    .indexOf
    Java函数。此函数返回集合中任何元素的索引,如果找不到此元素,则返回-1

    利用这一点,我们可以简单地说:

    (not= (.indexOf [1 2 3 4] 3) -1)
    => true
    

    “推荐”解决方案的问题是,当您要查找的值为“nil”时,它会中断。我更喜欢这个解决方案:

    (defn member? [list elt]
        "True if list contains at least one instance of elt"
        (cond 
            (empty? list) false
            (= (first list) elt) true
            true (recur (rest list) elt)))
    
    (defn member?
      "I'm still amazed that Clojure does not provide a simple member function.
       Returns true if `item` is a member of `series`, else nil."
      [item series]
      (and (some #(= item %) series) true))
    

    示例用法(which?[1 2 3]3)或(which?{1 2 3}4 5 3)

    有用于此目的的方便函数。特别是,函数
    包含elem?
    包含key?
    包含val?
    非常有用。有完整的文件

    包含元素?
    是最通用的,适用于向量或任何其他clojure
    seq

      (testing "vecs"
        (let [coll (range 3)]
          (isnt (contains-elem? coll -1))
          (is   (contains-elem? coll  0))
          (is   (contains-elem? coll  1))
          (is   (contains-elem? coll  2))
          (isnt (contains-elem? coll  3))
          (isnt (contains-elem? coll  nil)))
    
        (let [coll [ 1 :two "three" \4]]
          (isnt (contains-elem? coll  :no-way))
          (isnt (contains-elem? coll  nil))
          (is   (contains-elem? coll  1))
          (is   (contains-elem? coll  :two))
          (is   (contains-elem? coll  "three"))
          (is   (contains-elem? coll  \4)))
    
        (let [coll [:yes nil 3]]
          (isnt (contains-elem? coll  :no-way))
          (is   (contains-elem? coll  :yes))
          (is   (contains-elem? coll  nil))))
    
    这里我们看到,对于整数范围或混合向量,
    包含elem?
    对于集合中的现有元素和非现有元素都能正常工作。对于映射,我们还可以搜索任何键值对(表示为len-2向量):

    搜索集合也很简单:

      (testing "sets"
        (let [coll #{1 :two "three" \4}]
          (isnt (contains-elem? coll  :no-way))
          (is   (contains-elem? coll  1))
          (is   (contains-elem? coll  :two))
          (is   (contains-elem? coll  "three"))
          (is   (contains-elem? coll  \4)))
    
        (let [coll #{:yes nil}]
          (isnt (contains-elem? coll  :no-way))
          (is   (contains-elem? coll  :yes))
          (is   (contains-elem? coll  nil)))))
    
    对于地图和集合,使用
    contains key?
    查找地图条目或集合元素更简单(更高效):

    (deftest t-contains-key?
      (is   (contains-key?  {:a 1 :b 2} :a))
      (is   (contains-key?  {:a 1 :b 2} :b))
      (isnt (contains-key?  {:a 1 :b 2} :x))
      (isnt (contains-key?  {:a 1 :b 2} :c))
      (isnt (contains-key?  {:a 1 :b 2}  1))
      (isnt (contains-key?  {:a 1 :b 2}  2))
    
      (is   (contains-key?  {:a 1 nil   2} nil))
      (isnt (contains-key?  {:a 1 :b  nil} nil))
      (isnt (contains-key?  {:a 1 :b    2} nil))
    
      (is   (contains-key? #{:a 1 :b 2} :a))
      (is   (contains-key? #{:a 1 :b 2} :b))
      (is   (contains-key? #{:a 1 :b 2}  1))
      (is   (contains-key? #{:a 1 :b 2}  2))
      (isnt (contains-key? #{:a 1 :b 2} :x))
      (isnt (contains-key? #{:a 1 :b 2} :c))
    
      (is   (contains-key? #{:a 5 nil   "hello"} nil))
      (isnt (contains-key? #{:a 5 :doh! "hello"} nil))
    
      (throws? (contains-key? [:a 1 :b 2] :a))
      (throws? (contains-key? [:a 1 :b 2]  1)))
    
    对于地图,您还可以使用
    包含val?
    搜索值:

    (deftest t-contains-val?
      (is   (contains-val? {:a 1 :b 2} 1))
      (is   (contains-val? {:a 1 :b 2} 2))
      (isnt (contains-val? {:a 1 :b 2} 0))
      (isnt (contains-val? {:a 1 :b 2} 3))
      (isnt (contains-val? {:a 1 :b 2} :a))
      (isnt (contains-val? {:a 1 :b 2} :b))
    
      (is   (contains-val? {:a 1 :b nil} nil))
      (isnt (contains-val? {:a 1 nil  2} nil))
      (isnt (contains-val? {:a 1 :b   2} nil))
    
      (throws? (contains-val?  [:a 1 :b 2] 1))
      (throws? (contains-val? #{:a 1 :b 2} 1)))
    
    如测试中所示,当搜索
    nil
    值时,这些函数中的每一个都能正常工作。

    另一个选项:

    ((set '(100 101 102)) 101)
    
    使用java.util.Collection#contains():


    真奇怪,是吗?必须是Clojure中最容易引起误解的函数:)希望Clojure 1.3能将其重命名为contains key?或者类似的。我想这已经被说了好几次了。包含?不会改变。请看这里:@kotarak谢谢你的链接!实际上,我同意Rich在这里对contains的使用?尽管我认为应该修改名称,以便在应用于列表或序列时抛出错误谢谢Michal-你是一个字体o
      (testing "sets"
        (let [coll #{1 :two "three" \4}]
          (isnt (contains-elem? coll  :no-way))
          (is   (contains-elem? coll  1))
          (is   (contains-elem? coll  :two))
          (is   (contains-elem? coll  "three"))
          (is   (contains-elem? coll  \4)))
    
        (let [coll #{:yes nil}]
          (isnt (contains-elem? coll  :no-way))
          (is   (contains-elem? coll  :yes))
          (is   (contains-elem? coll  nil)))))
    
    (deftest t-contains-key?
      (is   (contains-key?  {:a 1 :b 2} :a))
      (is   (contains-key?  {:a 1 :b 2} :b))
      (isnt (contains-key?  {:a 1 :b 2} :x))
      (isnt (contains-key?  {:a 1 :b 2} :c))
      (isnt (contains-key?  {:a 1 :b 2}  1))
      (isnt (contains-key?  {:a 1 :b 2}  2))
    
      (is   (contains-key?  {:a 1 nil   2} nil))
      (isnt (contains-key?  {:a 1 :b  nil} nil))
      (isnt (contains-key?  {:a 1 :b    2} nil))
    
      (is   (contains-key? #{:a 1 :b 2} :a))
      (is   (contains-key? #{:a 1 :b 2} :b))
      (is   (contains-key? #{:a 1 :b 2}  1))
      (is   (contains-key? #{:a 1 :b 2}  2))
      (isnt (contains-key? #{:a 1 :b 2} :x))
      (isnt (contains-key? #{:a 1 :b 2} :c))
    
      (is   (contains-key? #{:a 5 nil   "hello"} nil))
      (isnt (contains-key? #{:a 5 :doh! "hello"} nil))
    
      (throws? (contains-key? [:a 1 :b 2] :a))
      (throws? (contains-key? [:a 1 :b 2]  1)))
    
    (deftest t-contains-val?
      (is   (contains-val? {:a 1 :b 2} 1))
      (is   (contains-val? {:a 1 :b 2} 2))
      (isnt (contains-val? {:a 1 :b 2} 0))
      (isnt (contains-val? {:a 1 :b 2} 3))
      (isnt (contains-val? {:a 1 :b 2} :a))
      (isnt (contains-val? {:a 1 :b 2} :b))
    
      (is   (contains-val? {:a 1 :b nil} nil))
      (isnt (contains-val? {:a 1 nil  2} nil))
      (isnt (contains-val? {:a 1 :b   2} nil))
    
      (throws? (contains-val?  [:a 1 :b 2] 1))
      (throws? (contains-val? #{:a 1 :b 2} 1)))
    
    ((set '(100 101 102)) 101)
    
    (.contains '(100 101 102) 101)