Заполните два списка разной длины с элементом по умолчанию для заполнения

Предположим, что у нас есть следующие списки разного размера:

val list1 = ("a", "b", "c")
val list2 = ("x", "y")

Теперь я хочу объединить эти 2 списка и создать новый список с конкатенированными строковыми элементами:

val desiredResult = ("ax", "by", "c")

Я пробовал

val wrongResult = (list1, list2).zipped map (_ + _)

как предложено здесь, но это не работает так, как предполагалось, потому что zip отбрасывает те элементы более длинного списка, которые невозможно сопоставить.

Как я могу решить эту проблему? Есть ли способ застегнуть списки и дать "элемент по умолчанию" (например, пустую строку в этом случае), если один список длиннее?

Ответ 1

Метод, который вы ищете, .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 принимает 3 аргумента:

  • Итерируемый для zip с
  • значение по умолчанию, если this (вызывается коллекция .zipAll) короче
  • значение по умолчанию, если другая коллекция короче

Ответ 2

Основанный на 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) 
  }
}

Отсюда, например,

Seq(1,2).zipAll2(Seq(3,4,5),10,20)
List((1,3), (2,4), (10,5))

и

list1.zipAll2(list2, "", "")
List((a,x), (b,y), (c,""))

Рекурсивная версия,

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

со значениями по умолчанию xd и по умолчанию yd.