'Zip two lists of different lengths with default element to fill
Assume we have the following lists of different size:
val list1 = ("a", "b", "c")
val list2 = ("x", "y")
Now I want to merge these 2 lists and create a new list with the string elements being concatenated:
val desiredResult = ("ax", "by", "c")
I tried
val wrongResult = (list1, list2).zipped map (_ + _)
as proposed here, but this doesn't work as intended, because zip discards those elements of the longer list that can't be matched.
How can I solve this problem? Is there a way to zip the lists and give a "default element" (like the empty string in this case) if one list is longer?
Solution 1:[1]
The API-based zipAll is the way to go, yet you can implement it (as an exercise) for instance as follows,
implicit class OpsSeq[A,B](val xs: Seq[A]) extends AnyVal {
def zipAll2(ys: Seq[B], xDefault: A, yDefault: B) = {
val xs2 = xs ++ Seq.fill(ys.size-xs.size)(xDefault)
val ys2 = ys ++ Seq.fill(xs.size-ys.size)(yDefault)
xs2.zip(ys2)
}
}
Hence for instance
Seq(1,2).zipAll2(Seq(3,4,5),10,20)
List((1,3), (2,4), (10,5))
and
list1.zipAll2(list2, "", "")
List((a,x), (b,y), (c,""))
A recursive version,
def zipAll3[A,B](xs: Seq[A], ys: Seq[B], xd: A, yd: B): Seq[(A,B)] = {
(xs,ys) match {
case (Seq(), Seq()) => Seq()
case (x +: xss, Seq()) => (x,yd) +: zipAll3(xss, Seq(), xd, yd)
case (Seq(), y +: yss) => (xd,y) +: zipAll3(Seq(), yss, xd, yd)
case (x +: xss, y +: yss) => (x,y) +: zipAll3(xss, yss, xd, yd)
}
}
with default xd and default yd values.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
