scala 使用要填充的默认元素压缩两个不同长度的列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35405607/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 08:01:02  来源:igfitidea点击:

Zip two lists of different lengths with default element to fill

scalafunctional-programming

提问by ForceOfWill

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:

现在我想合并这 2 个列表并创建一个新列表,其中字符串元素被连接:

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.

正如此处所建议的那样,但这并不像预期的那样工作,因为 zip 会丢弃无法匹配的较长列表中的那些元素。

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?

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

回答by Marth

The method you are looking for is .zipAll:

您正在寻找的方法是.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,""))


.zipAlltakes 3 arguments:

.zipAll需要 3 个参数:

  • the iterable to zip with
  • the default value if this(the collection .zipAllis called on) is shorter
  • the default value if the other collection is shorter
  • 可迭代的压缩
  • 如果this(集合.zipAll被调用)的默认值更短
  • 如果另一个集合较短,则为默认值

回答by elm

The API-based zipAllis the way to go, yet you can implement it (as an exercise) for instance as follows,

基于 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) 
  }
}

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 xdand default ydvalues.

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