Found bug in contains? used with vectors.

172 views
Skip to first unread message

Goldritter

unread,
Sep 3, 2012, 7:03:07 AM9/3/12
to clo...@googlegroups.com
I use Clojure 1.4.0 and wanted to use 'contains?' on a vector and get following results:

=> (contains? [1 2 3] 3)
false
=> (contains? [1 2 3] 2)
true

As it seems 'contains?' does not check for the last entry in the vector.

And an other question.
Why does contains? returns everytime 'false' when used on a list?
=> (contains? (list 1 2 3) 1)
false
=> (contains? (list 1 2 3) 2)
false
=> (contains? (list 1 2 3) 3)
false

Ambrose Bonnaire-Sergeant

unread,
Sep 3, 2012, 7:05:25 AM9/3/12
to clo...@googlegroups.com
'contains?' tests if a key is in a collection.

Vector is an associative data structure, with keys being indexes.
A vector of length 3 has the key 2, but not key 3.

Thanks,
Ambrose



--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Mayank Jain

unread,
Sep 3, 2012, 7:13:38 AM9/3/12
to clo...@googlegroups.com
From the book Clojure Programming, Page 101 :

"It is a common mistake for Clojure programmers to initially believe that contains? always searches for the presence of a value in a collection, that is, that it would be appropriate to use to determine if the vector [0 1 2 3] contained a particular numeric value. This misconception can lead to some very confusing results:

(contains? [1 2 3] 3)
;= false


(contains? [1 2 3] 2)
;= true

(contains? [1 2 3] 0)
;= true

Of course, the results above are correct, since contains? is only checking to see if any mapping exists for the provided key—in this case, the indices 3, 2, and 0. To check for the existence of a particular value in a collection, it is typical to use some


Goldritter

unread,
Sep 3, 2012, 7:14:35 AM9/3/12
to clo...@googlegroups.com, abonnair...@gmail.com
Ah ok. So I need to transform a vector and/or a list into a set first.

Thanks.

Tassilo Horn

unread,
Sep 3, 2012, 7:29:21 AM9/3/12
to clo...@googlegroups.com, abonnair...@gmail.com
Goldritter <marcus.goldr...@googlemail.com> writes:

> Ah ok. So I need to transform a vector and/or a list into a set first.

No, not really. All clojure collections implement java.util.Collection,
so you can always use

(.contains your-coll something)

to check if your-coll contains something. However, keep in mind that
this does a linear search for lists, sequences or vectors. So if your
algorithm relies on containment checks, you might be better off using
sets directly.

Bye,
Tassilo

Jim - FooBar();

unread,
Sep 3, 2012, 7:29:42 AM9/3/12
to clo...@googlegroups.com
this is probably the single most confusing name in clojure! :-) 
why can't we make it "contains-key?" ?

Jim

greg r

unread,
Sep 3, 2012, 7:43:05 AM9/3/12
to clo...@googlegroups.com
You could try the function some.

=> (some #{3} [1 2 3])
3
=> (some #{3} [1 2 5])
nil

This uses a set as a predicate function.

Greg

dmirylenka

unread,
Sep 4, 2012, 2:58:55 AM9/4/12
to clo...@googlegroups.com
As for contains? behavior on lists, it is fixed (CLJ-932) in Clojure 1.5, some 17 days ago:

=> (contains? '(1 2 3) 2); 
IllegalArgumentException contains? not supported on type: clojure.lang.PersistentList ...

I wonder if get is also going to be fixed?

=> (get [1 2 3] 2)
3
=> (get '(1 2 3) 2)
nil

Marcus Lindner

unread,
Sep 4, 2012, 5:01:51 AM9/4/12
to clo...@googlegroups.com
I think this is not a bad idea. ;)
At all, a method/function name should describe what it does. And if 'contains?' only looks for keys, then 'contains-key?' would be a better descriptor for it.

Marcus Lindner

unread,
Sep 4, 2012, 5:09:44 AM9/4/12
to clo...@googlegroups.com
I wanted to use it to select a random element in a collection (set,
vector or list) where I can define elements which should not be selected.
The function I now use is:

(defn select-random [collection & unselect]
"(select-random collection & unselect) selects a random element from
the specified 'collection'.
It will ignore any element which is specified in 'unselect'. If none
elements are specified in 'unselect',
then any element from the specified 'collection' may be chosen. "
( let [predicate #(contains? (set unselect) %1)]
(rand-nth (remove predicate collection))))

Eventually this can be optimized for better reading and/or performance.
It might be also a good idea to add some preconditions to it like
{pre: [(coll? collection)] }.

dmirylenka

unread,
Sep 4, 2012, 5:22:04 AM9/4/12
to clo...@googlegroups.com, marcus.goldr...@googlemail.com
Instead of

(let [predicate #(contains? (set unselect) %1)] ...)

I would write

(let [predicate (set unselect)] ...)

Jim - FooBar();

unread,
Sep 4, 2012, 7:35:53 AM9/4/12
to clo...@googlegroups.com
personally I've gotten used to it but it seems that every couple of weeks someone else will be confused and try to use contains? as it would be used in Java...the docs are clear but unfortunately not everyone consults the docs beforehand! at least not for such a semantically clear name as "contains?"...

Jim

Ben Smith-Mannschott

unread,
Sep 4, 2012, 7:51:07 AM9/4/12
to clo...@googlegroups.com
The naming of contains? is one of Clojure's small warts. Almost
everyone seems to stumble over it when they're starting out. I know I
did. Naming it contains-key? would have prevented a great deal of
confusion, but I guess that ship has sailed... *shrug*

// ben

Wolodja Wentland

unread,
Sep 5, 2012, 5:42:04 AM9/5/12
to clo...@googlegroups.com
On Tue, Sep 04, 2012 at 13:51 +0200, Ben Smith-Mannschott wrote:
> The naming of contains? is one of Clojure's small warts. Almost
> everyone seems to stumble over it when they're starting out. I know I
> did. Naming it contains-key? would have prevented a great deal of
> confusion, but I guess that ship has sailed... *shrug*

Has it? I would personally rather like to see this changed now than
seeing similar posts in five, ten or fifteen years.
--
Wolodja <bab...@gmail.com>

4096R/CAF14EFC
081C B7CD FF04 2BA9 94EA 36B2 8B7F 7D30 CAF1 4EFC
signature.asc
Reply all
Reply to author
Forward
0 new messages