Clojure for the brave and true exercise


I am going through the book exercises, specifically exercise 4 from the 3rd chapter which says: write a function mapset that works like map but the return value is a set. Here is my solution:

(defn mapset
  [f col]
  (let [res (map f col)]
    (loop [remaining res s #{}]
      (if (empty? remaining)
        (let [[head & tail] remaining]
          (recur tail (into s (set [head]))))))))

the output of (mapset #(+ % 1) [1 1 2 2]) should be #{2 3} but my solution is returning #{3 2} weirdly :face_with_raised_eyebrow: I know the sets are equal but I would expect REPL to print #{2 3}


Sets have no order guarantee so don’t worry about it: #{2 3} and #{3 2} are the same thing.


Also instead of (into s (set [head])) I’d write (conj s head), because that’s what you want: add element to a set. You can look at into as a multiple conjes over a collection of elements, which in your case was a collection of one element: head, so there is no need to use a collection function.


Also regarding (set [head]) in into: second argument to into is a collection, all elements of which will be conjed to collection passed as first argument. Type of second argument collection, be it a set, a vector or something else, does not matter, result collection type will be the same as first collection’s type, so you can safely replace (set [head]) with just [head] (though just using conj is still better)


Since you already know about into, you can avoid the explicit recursion by leveraging into. As @vlaaad points out, into can be thought of as conjing each element of the second collection argument to the first collection argument. Thus, your mapset function using just into and map:

(defn mapset [f coll] (into #{} (map f coll)))

This way of looking at the solution can also lead you down the path of transducers, but I would suggest leaving them until you feel comfortable with transforming collections the straightforward way.


Thanks for the tip !