What is the best way to test whether a list contains a given value in Clojure?
In particular, the behaviour of contains? is currently confusing me:
(contains? '(100 101 102) 101) => false
I could obviously write a simple function to traverse the list and test for equality, but there must surely be a standard way to do this?
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
getor, 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)istrue) and vectors (but note that(contains? [:foo :bar] 0)istrue, because the keys here are indices and the vector in question does “contain” the index0!).To add to the confusion, in cases where it doesn’t make sense to callUpdate: In Clojure ≥ 1.5contains?, it simply returnfalse; 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:
When searching for one of a bunch of items, you can use a larger set; when searching for
false/nil, you can usefalse?/nil?— because(#{x} x)returnsx, thus(#{nil} nil)isnil; when searching for one of multiple items some of which may befalseornil, you can use(Note that the items can be passed to
zipmapin any type of collection.)