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?
You can also zip two lists in python with the combination of zip() function and for loop. It is the least used method where the interlist aggregation can be done with the chain function, while the intralist aggregation can be done with the zip() function.
In Python, the built-in function zip() aggregates multiple iterable objects (lists, tuples, etc.). You can iterate multiple lists in the for loop with zip() .
This means, that if you pass in a list that is 5 items long, and another list that is one million items long, you’ll end up with a zip item that contains five items. Let’s verify this by zipping two lists of different lengths:
The following syntax shows how to zip together two lists of equal length into a dictionary: #define list of keys and list of values keys = ['a', 'b', 'c'] values = [1, 2, 3] #zip the two lists together into one dictionary dict (zip(keys, values)) {'a': 1, 'b': 2, 'c': 3} Example 3: Zip Two Lists of Unequal Length
Zipping lists of unequal or different lengths results in a zip object that is as long as the shortest iterable in the items being passed in. This means, that if you pass in a list that is 5 items long, and another list that is one million items long, you’ll end up with a zip item that contains five items.
The following syntax shows how to zip together two lists of equal length into a dictionary: If your two lists have unequal length, zip () will truncate to the length of the shortest list: If you’d like to prevent zip () from truncating to the length of the shortest list, you can instead use the zip_longest () function from the itertools library.
The method you are looking for is .zipAll
:
scala> val list1 = List("a", "b", "c") list1: List[String] = List(a, b, c) scala> val list2 = List("x", "y") list2: List[String] = List(x, y) scala> list1.zipAll(list2, "", "") res0: List[(String, String)] = List((a,x), (b,y), (c,""))
.zipAll
takes 3 arguments:
this
(the collection .zipAll
is called on) is shorterThe 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With