代码之家  ›  专栏  ›  技术社区  ›  mikera

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

  •  146
  • mikera  · 技术社区  · 14 年前

    contains? 我现在很困惑:

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

    17 回复  |  直到 8 年前
        1
  •  219
  •   Michał Marczyk    9 年前

    contains? ... 应该是五大常见问题之一:Clojure。

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

    更让人困惑的是,如果打电话没有意义 包含? ,它只是返回 false (contains? :foo 1) 还有 (contains? '(100 101 102) 101) . 更新: 包含? 当对象的类型不支持预期的“密钥成员资格”测试时抛出。

    正确的方法如下:

    ; most of the time this works
    (some #{101} '(100 101 102))
    

    / nil ,您可以使用 false? / nil? --因为 (#{x} x) 退货 x (#{nil} nil)

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

    (请注意,这些项可以传递给 zipmap 在任何类型的集合中。)

        2
  •  138
  •   nha    9 年前

    (defn in? 
      "true if coll contains elm"
      [coll elm]  
      (some #(= elm %) coll))
    
        3
  •  21
  •   Yury Litvinov    9 年前

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

    (.contains [100 101 102] 101) => true
    
        4
  •  18
  •   Aliaksandr Sushkevich    6 年前

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

    (contains? (set '(101 102 103)) 102)
    

    最后在clojure 1.4中输出true:)

        5
  •  12
  •   Felipe Augusto Ak S    5 年前
    (not= -1 (.indexOf '(101 102 103) 102))
    

    工作,但下面更好:

    (some #(= 102 %) '(101 102 103)) 
    
        6
  •  7
  •   mikera    14 年前

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

    (defn list-contains? [coll value]
      (let [s (seq coll)]
        (if s
          (if (= (first s) value) true (recur (rest s) value))
          false)))
    
        7
  •  6
  •   G__    14 年前

    以下是我的标准实用程序中的一个快速函数,我将其用于此目的:

    (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))))
    
        8
  •  6
  •   Community CDub    7 年前

    价值 你会发现 contains? 米莎已经 explained why .

    ; does not work as you might expect
    (contains? [:a :b :c] :b) ; = false
    

    1. 考虑一下你是否真的需要一个向量或列表。如果你 , 会有用的。

      (contains? #{:a :b :c} :b) ; = true
      
    2. 使用 some ,将目标包装在一个集合中,如下所示:

      (some #{:b} [:a :b :c]) ; = :b, which is truthy
      
    3. 如果正在搜索错误的值,“设置为函数”快捷方式将不起作用( false nil ).

      ; will not work
      (some #{false} [true false true]) ; = nil
      

      在这种情况下,你应该 对于这个值, false? nil? :

      (some false? [true false true]) ; = true
      
    4. 如果你需要经常做这种搜索, :

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

    Michał’s answer 检查是否 倍数 目标包含在一个序列中。

        9
  •  5
  •   Sergey Tselovalnikov    9 年前

    (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)))
    
        10
  •  4
  •   Community CDub    7 年前

    我建立在浮士德的基础上 version “列表包含?”。它现在需要任意数量的参数。

    (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))))
    
        11
  •  3
  •   Brad Koch Daniel Wright    10 年前

    它就像使用一个集合一样简单-就像地图一样,你可以把它放到函数的位置。如果在集合中(这是真的)或 nil (这是假的):

    (#{100 101 102} 101) ; 101
    (#{100 101 102} 99) ; nil
    

    如果您要检查一个大小合理的向量/列表,那么您也可以使用 set 功能:

    ; (def nums '(100 101 102))
    ((set nums) 101) ; 101
    
        12
  •  1
  •   KingCode    12 年前

    推荐的方法是 some 带一套-有关详细信息,请参阅文档 clojure.core/some

    你可以用 在真/假谓词中,例如。

    (defn in? [coll x] (if (some #{x} coll) true false))
    
        13
  •  1
  •   David    11 年前
    (defn in?
      [needle coll]
      (when (seq coll)
        (or (= needle (first coll))
            (recur needle (next coll)))))
    
    (defn first-index
      [needle coll]
      (loop [index 0
             needle needle
             coll coll]
        (when (seq coll)
          (if (= needle (first coll))
            index
            (recur (inc index) needle (next coll))))))
    
        14
  •  1
  •   Michael    8 年前
    (defn which?
     "Checks if any of elements is included in coll and says which one
      was found as first. Coll can be map, list, vector and set"
     [ coll & rest ]
     (let [ncoll (if (map? coll) (keys coll) coll)]
        (reduce
         #(or %1  (first (filter (fn[a] (= a %2))
                               ncoll))) nil rest )))
    

        15
  •  1
  •   Felipe Augusto Ak S    5 年前

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

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

    (not= (.indexOf [1 2 3 4] 3) -1)
    => true
    
        16
  •  0
  •   Simon Brooke    9 年前

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

    (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))
    
        17
  •  0
  •   Alan Thompson    8 年前

    为此有一些方便的功能 in the Tupelo library . 特别是功能 contains-elem? contains-key? ,和 contains-val? 非常有用。提供完整的文档 in the API docs .

    包含元素? 是最通用的,用于向量或任何其他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))))
    

    这里我们看到,对于整数范围或混合向量, 对集合中的现有元素和不存在的元素都按预期工作。对于映射,我们还可以搜索任何键值对(表示为len-2向量):

     (testing "maps"
        (let [coll {1 :two "three" \4}]
          (isnt (contains-elem? coll nil ))
          (isnt (contains-elem? coll [1 :no-way] ))
          (is   (contains-elem? coll [1 :two]))
          (is   (contains-elem? coll ["three" \4])))
        (let [coll {1 nil "three" \4}]
          (isnt (contains-elem? coll [nil 1] ))
          (is   (contains-elem? coll [1 nil] )))
        (let [coll {nil 2 "three" \4}]
          (isnt (contains-elem? coll [1 nil] ))
          (is   (contains-elem? coll [nil 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)))))
    

    包含密钥?

    (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 价值观。

        18
  •  0
  •   Alex    4 年前

    另一种选择:

    ((set '(100 101 102)) 101)
    

    使用java.util.Collection#contains():

    (.contains '(100 101 102) 101)