Test whether a list contains a specific value in Clojure
Ah, contains?
... supposedly one of the top five FAQs re: Clojure.
It does not check whether a collection contains a value; it checks whether an item could be retrieved with get
or, in other words, whether a collection contains a key. This makes sense for sets (which can be thought of as making no distinction between keys and values), maps (so (contains? {:foo 1} :foo)
is true
) and vectors (but note that (contains? [:foo :bar] 0)
is true
, because the keys here are indices and the vector in question does "contain" the index 0
!).
To add to the confusion, in cases where it doesn't make sense to call Update: In Clojure ≥ 1.5 contains?
, it simply return false
; this is what happens in (contains? :foo 1)
and also (contains? '(100 101 102) 101)
.contains?
throws when handed an object of a type that doesn't support the intended "key membership" test.
The correct way to do what you're trying to do is as follows:
; most of the time this works
(some #{101} '(100 101 102))
When searching for one of a bunch of items, you can use a larger set; when searching for false
/ nil
, you can use false?
/ nil?
-- because (#{x} x)
returns x
, thus (#{nil} nil)
is nil
; when searching for one of multiple items some of which may be false
or nil
, you can use
(some (zipmap [...the items...] (repeat true)) the-collection)
(Note that the items can be passed to zipmap
in any type of collection.)
Here's my standard util for the same purpose:
(defn in?
"true if coll contains elm"
[coll elm]
(some #(= elm %) coll))
You can always call java methods with .methodName syntax.
(.contains [100 101 102] 101) => true
I know that I'm a little bit late, but what about:
(contains? (set '(101 102 103)) 102)
At last in clojure 1.4 outputs true :)