clojure.set/union bug?

168 views
Skip to first unread message

Goldritter

unread,
Jul 1, 2013, 2:05:34 PM7/1/13
to clo...@googlegroups.com
I wanted to create a union of the keys from two maps.

When I write
(clojure.set/union (keys {:a 1 :b 2 :c 3}) (keys {:a 1 :b 2 :c 3}))
I get a result of (:b :c :a :a :c :b).
When I write (set (clojure.set/union (keys {:a 1 :b 2 :c 3}) (keys {:a 1 :b 2 :c 3})))
the result is #{:a :c :b}.

The document of clojure.set/union describes that the function "Return a set that is the union of the input sets".
As it seems the function keys does not return a set and so the returning result is not a set too. Correct?
And that this is the reason, that the keys are duplicated in the returning "list".

I wonder know is this is a bug or not. And what the normal behaviour of the function should be in this case?
Should it throw an Exception, because the passed parameters are not sets, should it return a set, even if the passed parameters are no sets or should the desciption of the function should be changed to express that a list (with eeventually duplicated entries) is returend, if the passed parameters are lists?

Jim - FooBar();

unread,
Jul 1, 2013, 2:25:26 PM7/1/13
to clo...@googlegroups.com
HI there,

It's pretty obvious what is happening....you are not providing sets to
union but rather seqs. in other words 'keys' return a seq not a set.
union will simply conj all the elements from the first set into the
second (or vice versa). if they are not sets they won't behave like sets...

in order to get what you want you need:

(clojure.set/union (set (keys {:a 1 :b 2 :c 3})) (set (keys {:a 1 :b 2
:c 3})))

hope that helps,

Jim
> --
> --
> 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
> ---
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to clojure+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Pablo Nussembaum

unread,
Jul 1, 2013, 3:02:45 PM7/1/13
to clo...@googlegroups.com
Hi,
This is pretty strange behavior to me, why is the case that keys
function don't return a set like java?
That could lead to a big penalty in performance if you don't realize
this difference.

I don't say that this is bug, although I would like to believe that a
nice explanation exists ;-)
Regards,
--
Bauna

Jim - FooBar();

unread,
Jul 1, 2013, 3:37:00 PM7/1/13
to clo...@googlegroups.com
On 01/07/13 20:02, Pablo Nussembaum wrote:
> This is pretty strange behavior to me, why is the case that keys
> function don't return a set like java?

It doesn't need to be, does it?...the map itself ensures that there are
no duplicate keys anyway. I guess it's one of those 'less is more' cases...

Jim

Mark Engelberg

unread,
Jul 1, 2013, 3:58:26 PM7/1/13
to clo...@googlegroups.com
Expanding on what Jim said, you don't usually need to convert the keys of a map into a set, because the map pretty much acts like a set of its keys if you use contains?

For example, (contains? {:a 1, :b 2} :a) tests whether :a is among the set of keys in the map.

I believe that clojure.set's union, intersection, and difference all work out of the box on maps (acting as if they are sets of keys), but you should do some testing and/or inspection of the source code to verify this, especially on maps with nil or false values.



--
--
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

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.

Cedric Greevey

unread,
Jul 1, 2013, 4:39:39 PM7/1/13
to clo...@googlegroups.com
It's likely that "keys" returns a seq because you might care about the order in the case that you call it in a sorted map, and you can always convert it to a set with "into #{}" or whatever.

What bugs me is that "sorted-set-by" needs "apply" to convert a coll into a sorted set; there's no short-and-pithy "into" for that case, and no coll-taking and varargs version pair like vec/vector either. There's also no "sorted-set-on first [[:a :b :c] [:x :y :z] [:a :c :b]]" (output would put the two :a-beginning vectors together) either -- you need a comparator. Some other core sort-related fns have versions taking a key-fn, but none that constructs a sorted set that I could see with a quick apropos of the documentation...




For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

Jim - FooBar();

unread,
Jul 1, 2013, 4:57:16 PM7/1/13
to clo...@googlegroups.com
On 01/07/13 21:39, Cedric Greevey wrote:
> It's likely that "keys" returns a seq because you might care about the
> order in the case that you call it in a sorted map, and you can always
> convert it to a set with "into #{}" or whatever.


aaaa yes, of course! I completely forgot the ordering issue...

Jim

Marcus Lindner

unread,
Jul 1, 2013, 11:56:21 PM7/1/13
to clo...@googlegroups.com
As it seems clojure.set/union can be used with maps as parameters too.
=>(clojure.set/union {:a 1 :b 2 :c 3 :d 4} {:a 1 :b 4 :c 4})
{:a 1, :c 4, :b 4, :d 4}

So it is possible to get a union of keys of a map with
=> (keys (clojure.set/union {:a 1 :b 2 :c 3 :d 4} {:a 1 :b 4 :c 4}))
(:a :c :b :d)

If I have a map with nil as key
=> (clojure.set/union {:a 1 :b 2 :c 3 nil 4} {:a 1 :b 4 :c 4 nil 7})
{nil 7, :a 1, :c 4, :b 4}

with 'false' as key
=>(clojure.set/union {:a 1 :b 2 :c 3 false 4} {:a 1 :b 4 :c 4 false 7})
{:a 1, :c 4, :b 4, false 7}

 with 'true' and 'false' as keys and value
=> (clojure.set/union {:a 1 true 2 :c 3 false true} {:a 1 true 4 :c 4 false 7})
{:a 1, :c 4, true 4, false 7}

clojure.set/intersection on the otherside throws an exception
=> (clojure.set/intersection {:a 1 :b 2 :c 3 :d 4} {:a 1 :b 4 :c 4})
ClassCastException clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1436)

The same for clojure.set/difference
(clojure.set/difference {:a 1 :b 2 :c 3 :d 4} {:a 1 :b 4 :c 4})
ClassCastException clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1436)

As it seems only union accepts nearly any type of collection where difference and intersection throws exception if the passed parameters are not sets.


Am 01.07.2013 21:58, schrieb Mark Engelberg:
Expanding on what Jim said, you don't usually need to convert the keys of a map into a set, because the map pretty much acts like a set of its keys if you use contains?

For example, (contains? {:a 1, :b 2} :a) tests whether :a is among the set of keys in the map.

I believe that clojure.set's union, intersection, and difference all work out of the box on maps (acting as if they are sets of keys), but you should do some testing and/or inspection of the source code to verify this, especially on maps with nil or false values.



On Mon, Jul 1, 2013 at 12:37 PM, Jim - FooBar(); <jimpi...@gmail.com> wrote:
On 01/07/13 20:02, Pablo Nussembaum wrote:
This is pretty strange behavior to me, why is the case that keys
function don't return a set like java?

It doesn't need to be, does it?...the map itself ensures that there are no duplicate keys anyway. I guess it's one of those 'less is more' cases...

Jim


--
--
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

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.


--
--
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

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

Ray Miller

unread,
Jul 2, 2013, 2:40:05 AM7/2/13
to clo...@googlegroups.com
On 1 July 2013 21:39, Cedric Greevey <cgre...@gmail.com> wrote: 
 
What bugs me is that "sorted-set-by" needs "apply" to convert a coll into a sorted set; there's no short-and-pithy "into" for that case, and no coll-taking and varargs version pair like vec/vector either.
 
(into (sorted-set) coll)

Cedric Greevey

unread,
Jul 2, 2013, 3:10:03 AM7/2/13
to clo...@googlegroups.com
Er...that won't use my custom comparator. :)


--

Ray Miller

unread,
Jul 2, 2013, 4:41:50 AM7/2/13
to clo...@googlegroups.com
On 2 July 2013 08:10, Cedric Greevey <cgre...@gmail.com> wrote:
Er...that won't use my custom comparator. :)

Sorry, I thought it was clear how to generalize from my previous example. Here it is with a custom comparator:

(into (sorted-set-by >) [1 2 4 2 1 2 3])
;; => #{4 3 2 1}

Cedric Greevey

unread,
Jul 2, 2013, 5:05:29 AM7/2/13
to clo...@googlegroups.com
Still seems verbose compared to (into #{}) ...


Reply all
Reply to author
Forward
0 new messages