Is there an equivalent for the Zip function in Clojure Core or Contrib?
In Clojure, I want to combine two lists to give a list of pairs,
> (zip '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
In Haskell or Ruby the function is called zip. Implementing it is not difficult, but I wanted to make sure I wasn't missing a function in Core or Contrib.
There is a zip namespace in Core, but it is described as providing access to the Zipper functional technique, which does not appear to be what I am after.
Is there an equivalent function for combining 2 or more lists, in this way, in Core?
If there is not, is it because there is an idiomatic approach that renders the function unneeded?
Solution 1:
(map vector '(1 2 3) '(4 5 6))
does what you want:
=> ([1 4] [2 5] [3 6])
Haskell needs a collection of zipWith
(zipWith3
, zipWith4
, ...) functions, because they all need to be of a specific type; in particular, the number of input lists they accept needs to be fixed. (The zip
, zip2
, zip3
, ... family can be regarded as a specialisation of the zipWith
family for the common use case of tupling).
In contrast, Clojure and other Lisps have good support for variable arity functions; map
is one of them and can be used for "tupling" in a manner similar to Haskell's
zipWith (\x y -> (x, y))
The idiomatic way to build a "tuple" in Clojure is to construct a short vector, as displayed above.
(Just for completeness, note that Haskell with some basic extensions does allow variable arity functions; using them requires a good understanding of the language, though, and the vanilla Haskell 98 probably doesn't support them at all, thus fixed arity functions are preferrable for the standard library.)
Solution 2:
(partition 2 (interleave '(1 2 3) '(4 5 6)))
=> ((1 4) (2 5) (3 6))
or more generally
(defn zip [& colls]
(partition (count colls) (apply interleave colls)))
(zip '( 1 2 3) '(4 5 6)) ;=> ((1 4) (2 5) (3 6))
(zip '( 1 2 3) '(4 5 6) '(2 4 8)) ;=> ((1 4 2) (2 5 4) (3 6 8))