# N-zip using unfold

We can implement the `zip` method using `unfold` as follows:

`````` def myZip(a: List[Int], b: List[Int]) ={
List.unfold(a, b){
case(a, b) if a.length > 0 & b.length >0 => Some( (a.head, b.head), (a.tail, b.tail))
case _ => None
}
}
``````

It is easy to generalize this method to any finite number of lists to be zipped. But I cannot come up with an idea how to define a general zip function operating on unspecified in advance number of lists. Can you please give some hints?

The problem with generalisation is the output type, a `zipN` method would return a `List[List[Any]]` or a `List[List[A]]` the first one is not really useful, and the second one is usually called transpose instead.

BTW, you should prefer pattern matching there:

``````def myZip[A, B](as: List[A], bs: List[B]): List[(A, B)] =
List.unfold((as, bs)) {
case (a :: tailA, b :: tailB) =>
Some((a, b), (tailA, tailB))

case _ =>
None
}
``````
3 Likes

@BalmungSan Thanks a lot, really useful!

But how can I use `transpose` here
`(List(1,2,3), List("a","b","c"), List(1.0, 2.0, 3.0)).transpose`

Is patter matching serves any other purpose besides replacing my awkward length check?

It makes the code prettier (subjective) and arguably safer (objective)

Well, you can’t.
Frist things first, `transponse` is not a method on tuples, is a method on `List` (or any other collection).
Second, in that case, your result would be a `List[List[Any]]` which as I said, is not really useful at all.
You can see the implementation of such method here: Scastie - An interactive playground for Scala.

That is why I said that an arbitrary and useful `zipN` in current Scala is not simple to implement.
Alternatives could be, using source generators to generate enough overloads for most use cases; this is what cats does, or exploring a typeclass approach with implicit derivation for any tuple.

3 Likes

You are amazing, thanks for the code!

By the way, in your resulting type parametrization you probably have to use `List[(A, B)]`, i.e., list of tuples (at least in scala 2)

Where? In the implementation of `transponse`? Again, not possible, that is all I have been saying all along.

In the code that you posted above

``````def myZip[A, B](as: List[A], bs: List[B]): List[A, B] =
List.unfold((as, bs)) {
case (a :: tailA, b :: tailB) =>
Some((a, b), (tailA, tailB))

case _ =>
None
}
``````

It is a minor thing, it just gives an error with `List[A, B]` and works fine with `List[(A, B)]`.

Oh, ah, right; sorry for that, just fixed it Thanks!

1 Like

Hi @yarchik, FWIW, just in case you find them of interest, here are some other alternatives:

``````def zip[A,B](l1: List[A], l2: List[B]): List[(A,B)] = (l1,l2) match
case (a :: as, b :: bs) => (a,b) :: zip(as,bs)
case _ => Nil

def zip[A,B](as: List[A], bs: List[B]): List[(A,B)] =
if as.isEmpty || bs.isEmpty then Nil