4

Given a map {:a 1 :b [2,3]}, is there a built-in function which would return the sequence (:a 1 :b [2,3]).

The use case is applying an options map to a function which does map-destructured binding on the remainder of an argument list. Here's an example of this in core.cache. Here's a contrived example to illustrate:

(defn make-car [& {:as options}] (assoc options :car true))
(make-car :color "red" :speed "fast")
; => {:car true, :speed "fast", :color "red"}

Now if we want to manage the options separately and apply them to the function, we have a problem:

(def options {:color "red" :speed "fast"})
(apply make-car options)
; => {:car true, [:speed "fast"] [:color "red"]}

...because of course the seq of a map is a sequence of its key-value pairs. This is the best I've come up with:

(apply make-car (interleave (keys options) (vals options)))
; => {:car true, :speed "fast", :color "red"}

This is pretty awful. I know I could just make my own function to do this, but I'm surprised I haven't found something built-in. If there isn't something built-in, then I'd probably want to avoid destructuring argument lists like this in library code.

James MacAulay
  • 317
  • 2
  • 6
  • I believe you're looking for this: http://clojuredocs.org/clojure_contrib/clojure.contrib.test-is/flatten-map Apparently it didn't make it into core. I agree that this is a bit weird though. PS: `(comp (partial apply concat) seq)` imho looks a bit better than interleave, though a builtin would of course have been better. – Cubic Oct 07 '12 at 16:44

1 Answers1

5

How about this:

(reduce concat {:a 1 :b [2,3]})
(:a 1 :b [2 3])

Update based on the comment from amalloy. Apply is more efficient (at least in 1.4), and achieves the same result!

(apply concat {:a 1 :b [2,3]})
(:a 1 :b [2 3])
Eve Freeman
  • 32,467
  • 4
  • 86
  • 101
  • 2
    `(reduce concat)` is very dangerous for large sequences, and needlessly inefficient for small ones. Use `(apply concat)` instead. – amalloy Oct 07 '12 at 21:43
  • What makes it dangerous for large sequences? – James MacAulay Oct 07 '12 at 22:32
  • Hey, thanks @amalloy. I ran some tests and you are definitely right about apply being faster. Correcting the answer, with a note. – Eve Freeman Oct 08 '12 at 00:58
  • As far as being dangerous--I suppose it might stack overflow, or just be dangerously slow. – Eve Freeman Oct 08 '12 at 01:05
  • Try `(first (f concat (repeat 1e5 [1])))`, substituting `apply` and `reduce` for `f`. See http://stackoverflow.com/questions/2946764/recursive-function-causing-a-stack-overflow for a description of similar code with the same problem. – amalloy Oct 08 '12 at 02:49