2016-02-15 12 views
10

Angenommen, wir folgende Listen unterschiedlicher Größe haben:Zip zwei Listen unterschiedlicher Länge mit Standardelement zu füllen

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

Jetzt möchte ich diese 2-Listen verschmelzen und eine neue Liste mit den String-Elementen erstellen verkettet werden :

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

ich versuchte

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

als here vorgeschlagen, Dies funktioniert jedoch nicht wie vorgesehen, da zip die Elemente der längeren Liste verwirft, die nicht zugeordnet werden können.

Wie kann ich dieses Problem lösen? Gibt es eine Möglichkeit, die Listen zu komprimieren und ein "Standardelement" (wie die leere Zeichenfolge in diesem Fall) zu geben, wenn eine Liste länger ist?

Antwort

26

Verfahren Sie suchen, ist .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 dauert 3 Argumente:

  • die iterable mit
  • der Standardwert, wenn this (die Sammlung zip .zipAll wird aufgerufen) ist kürzer
  • der Standardwert, wenn die andere Sammlung kürzer
+1

Ich denke, es gibt immer etwas, von dem man nichts weiß. –

+0

Danke! Nun funktioniert es mit dieser Lösung: 'list1.zipAll (list2," "," ") map ({case (y, x) => y + x})' aber nicht wie vorher mit 'list1.zipAll (list2," "," ") map (_ + _)'. Warum kann ich die kurze Syntax mit dem ZipAll nicht wie die Zip-Funktion verwenden? – ForceOfWill

+1

@ForceOfWill: '(list1, list2) .zipped' gibt ein' Tuple2Zipped' zurück, wobei ['.map'] (http://www.scala-lang.org/api/current/index.html#scala.runtime .Tuple2Zipped @ map [B, Bis] (f: (El1, El2) => B) (implizitcbf: scala.collection.generic.CanBuildFrom [Repr1, B, To]): To) nimmt ein 'f: (El1, El2) => B' (dh eine Funktion, die 2 Argumente akzeptiert). 'List [A]' s '.map' nimmt ein' f: A => B', dh nur 1 Argument (was in diesem Fall ein 'Tuple2' ist). Leider bedeutet dies, dass '_ + _' (was eine Funktion ist, die 2 Argumente benötigt) hier nicht angewendet werden kann. – Marth

2

Die API-basierte zipAll ist der Weg zu gehen, aber man kann es zum Beispiel implementieren (als Übung) wie folgt

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

daher zum Beispiel

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

und

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

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

mit Standard xd und Standard yd Werte.

Verwandte Themen