I spent 30 minutes today learning that contains?
has surprising (to me at least) behavior on indexed collections. I expected it to tell me whether the vector contains an item and indeed this is how it works on collections like lists, sets, maps, etc.
For example:
user=> (contains? #{ "a" "b"} "a") true user=> (contains? { :a 1 :b 2 } :a) true user=> (contains? ["a" "b" ] "a") false
What? Check the docs:
user=> (doc contains?) ------------------------- clojure.core/contains? ([coll key]) Returns true if key is present in the given collection, otherwise returns false. Note that for numerically indexed collections like vectors and Java arrays, this tests if the numeric key is within the range of indexes. 'contains?' operates constant or logarithmic time; it will not perform a linear search for a value. See also 'some'.
So for structures like vectors and arrays, the contains?
function expects a numerical argument that is an index, not an item.
user=> (contains? ["a" "b"] 0) true user=> (contains? ["a" "b"] 1) true user=> (contains? ["a" "b"] 2) false
I don’t have a better solution at hand for how to do this with vectors and arrays. I’d love to see one.
Update from @fogus:
user=> (some #{"b"} ["a" "b"]) "b" user=> (some #{"d"} ["a" "b"]) nil
For the purposes of logical true/false, the “b” will evaluate to true. I’ll just say that’s pretty obscure in my book.
Update #2: Some useful info here too on this subject. Thanks @wmacgyver.