Clojure: Equivalent to Scala's flatMap/C#'s SelectMany
I’ve been playing around with Clojure a bit over the weekend and one thing I got stuck with was working out how to achieve the functionality provided by Scala’s flatMap or C#'s SelectMany methods on collections.
I had a collection of zip files and wanted to transform that into a collection of all the file entries in those files.
If we just use map then we’ll end up with a collection of collections which is more difficult to deal with going forward.
In Scala we’d do the following:
import scala.collection.JavaConversions._ val zip1 = new ZipFile(new File("/Users/mneedham/Documents/my-zip-file.zip")) val zip2 = new ZipFile(new File("/Users/mneedham/Documents/my-zip-file2.zip")) List(zip1, zip2).flatMap(_.entries)
I was originally make using of map followed by flatten but I learnt from my colleague Phil Calcado that the function I wanted is http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/mapcat which leads to this solution:
(def zip1 (new ZipFile (file "/Users/mneedham/Documents/my-zip-file.zip"))) (def zip2 (new ZipFile (file "/Users/mneedham/Documents/my-zip-file2.zip"))) (mapcat (fn [file] (enumeration-seq (.entries file))) (list zip1 zip2))
I also learnt about the various functions available to create sequences, such as enumeration-seq from other types which are listed at the bottom of this page.
Scala uses implicit conversions to do that and presumably you’d hide away the conversion in a helper function in Clojure.