joaquinlpereyra
joaquinlpereyra

Reputation: 966

Weird order in sets in Clojure

So, I'm trying to work my way through Brave Clojure. The third exercise consists on creating a map function but instead of returning a list it should return a set. OK, so there I go:

(defn mapset
  [f lst]
  (loop [[head & remaining] lst
         final-set #{}]
    (if (empty? remaining)
      (into final-set #{(f head)})
      (recur remaining
             (into final-set #{(f head)})))))

But then something weird happens. The function works, kind of. But the order is all messed up in the sets. I know that in mathematics order in sets is irrelevant, but I can't keep from wondering why is this happening:

clojure-noob.core=> (mapset identity [1])
#{1}
clojure-noob.core=> (mapset identity [1 2])
#{1 2}
clojure-noob.core=> (mapset identity [1 2 3])
#{1 3 2}
clojure-noob.core=> (mapset identity [1 2 3 4])
#{1 4 3 2}
clojure-noob.core=> (mapset identity [1 2 3 4 5])
#{1 4 3 2 5}
clojure-noob.core=> (mapset identity [1 2 3 4 5 6])
#{1 4 6 3 2 5}

It's not only the identity function either.

clojure-noob.core=> (mapset inc [1 2 3])
#{4 3 2}

What's happening here?

Upvotes: 0

Views: 603

Answers (2)

Alan Thompson
Alan Thompson

Reputation: 29958

As ymonad said, Clojure sets are "randomly" ordered:

> (println #{ 1 2 3 4 5 } )
#{1 4 3 2 5}

The literal set syntax #{1 2 3 4 5} is just short for (hash-set ...). You can get a sorted set as shown:

> (hash-set 1 2 3 4 5 6)
#{1 4 6 3 2 5}
> (sorted-set 1 2 3 4 5 6)
#{1 2 3 4 5 6}
> (into (sorted-set) #{1 2 3 4 5 6} )
#{1 2 3 4 5 6}

In the last example, we use into to add elements from the regular set into an empty sorted-set

Upvotes: 5

Matthias Wimmer
Matthias Wimmer

Reputation: 3999

Sets are by default unordered. Therefore your results are fine, they contain the right elements. In general order is not important for sets.

Upvotes: 3

Related Questions