使用默认元素压缩两个不同长度的列表以进行填充

For*_*ill 14 functional-programming scala

假设我们有以下不同大小的列表:

val list1 = ("a", "b", "c")
val list2 = ("x", "y")
Run Code Online (Sandbox Code Playgroud)

现在我想合并这两个列表并创建一个新的列表,其中串联的字符串元素:

val desiredResult = ("ax", "by", "c")
Run Code Online (Sandbox Code Playgroud)

我试过了

val wrongResult = (list1, list2).zipped map (_ + _)
Run Code Online (Sandbox Code Playgroud)

正如这里提出的那样,但是这不能按预期工作,因为zip会丢弃那些无法匹配的较长列表中的元素.

我怎么解决这个问题?有没有办法压缩列表并给出一个"默认元素"(如本例中的空字符串),如果一个列表更长?

Mar*_*rth 36

您正在寻找的方法是.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,""))
Run Code Online (Sandbox Code Playgroud)

.zipAll 需要3个参数:

  • 压缩的可迭代
  • if this(.zipAll调用集合)的默认值更短
  • 如果其他集合较短,则为默认值


elm*_*elm 6

基于 API 的方法zipAll是可行的,但您可以实现它(作为练习),例如,如下所示,

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) 
  }
}
Run Code Online (Sandbox Code Playgroud)

因此例如

Seq(1,2).zipAll2(Seq(3,4,5),10,20)
List((1,3), (2,4), (10,5))
Run Code Online (Sandbox Code Playgroud)

list1.zipAll2(list2, "", "")
List((a,x), (b,y), (c,""))
Run Code Online (Sandbox Code Playgroud)

递归版本,

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) 
  }
}
Run Code Online (Sandbox Code Playgroud)

带有默认值xd和默认yd值。