2017-11-22 1 views
2

Ich habe eine Liste von Tuple-2 wie folgt aus:Kann ich in Scala eine Liste überlagern und gleichzeitig erweitern?

val stuff = List(("!thing","value"), ("otherthing","value")) 

Ich möchte über diese Liste zu übergeben und Objekte aus dem Inhalt wie folgt erstellen:

val processed = stuff.map{ case (label, value) => 
    if(label.startsWith("!")) 
    BigThing(label.tail,value) // extends trait Thing 
    else 
    LittleThing(label,value) . // extends trait Thing 
} 

So weit so gut. Nun die Frage ...

Während ich über diese Tupel zuordnen, wenn das Label mit "!" Beginnt, möchte ich auch ein Bonus(label.tail) Objekt erstellen (erweitert auch die Eigenschaft Thing) und dieses Objekt zur resultierenden Liste hinzufügen . Dies bedeutet, dass eine Eingabeliste von n Elementen eine Liste von> n Elementen ergeben kann. Was ist die rationellste funktionale Lösung dafür?

Der endgültige Ausgang gewünscht ist eine erweiterte Liste von Thing. So das obige Beispiel würde erzeugen theoretisch (Reihenfolge unwichtig):

List(BigThing("thing","value"), Bonus("thing"), LittleThing("otherthing","value")) 

Antwort

3

ich flatMap dafür verwenden würde:

val processed = stuff.flatMap { case (label, value) => 
    if (label.startsWith("!")) 
    List(BigThing(label.tail, value), Bonus(label.tail)) 
    else 
    List(LittleThing(label, value)) 
} 

Ergebnis:

List(BigThing(thing,value), Bonus(thing), LittleThing(otherthing,value)) 
+0

prüfen dies als die beste Antwort. Eigentlich funktionierte die foldLeft-Antwort unten besser für meinen speziellen Gebrauch, aber die flatMap ist die bessere Antwort im Allgemeinen. – Greg

2

Wie wäre es foldLeft:

val processed = stuff.foldLeft(List.empty[Thing]) { case (list, (label, value)) => 
    if (label.startsWith("!")) { 
    list ++ (BigThing(label.tail, value) :: Bonus(label.tail) :: Nil) 
    } else list :+ LittleThing(label,value) 
} 
0

Da gibt es bereits Antworten auf die Frage, aber wenn wir feststellen, dass der Rückgabetyp List[Product with Serializable] ist, weil Sie versuchen, eine Liste zu erstellen, die nicht in Beziehung stehende Fallklassen enthält, kommt dies nicht in die Best Practice.

Ex:

scala> val processed = stuff.flatMap { case (label, value) => 
    | if (label.startsWith("!")) 
    |  List(BigThing(label.tail, value), Bonus(label.tail)) 
    | else 
    |  List(LittleThing(label, value)) 
    | } 
processed: List[Product with Serializable] = List(BigThing(thing,value), Bonus(thing), LittleThing(otherthing,value)) 

Wir können es entfernen, indem sie explizit Rückgabetyp. Da wir die Liste der verschiedenen Fallklassen zurückgeben, können wir Lis[Any] verwenden.

Ex:

scala> trait Thing extends Product with Serializable 
defined trait Thing 

scala> case class BigThing(id: String, value: String) extends Thing 
defined class BigThing 

scala> case class Bonus(id: String) extends Thing 
defined class Bonus 

scala> case class LittleThing(id: String, value: String) extends Thing 
defined class LittleThing 

scala> val stuff = List(("!thing","value"), ("otherthing","value")) 
stuff: List[(String, String)] = List((!thing,value), (otherthing,value)) 

scala> val result = stuff.flatMap { case (label, value) => 
    |   label match { 
    |   case lable if label.startsWith("!") => List(BigThing(label.tail, value), Bonus(label.tail)) 
    |   case _ => List(LittleThing(label, value)) 
    |   } 
    |  } 
result: List[Thing] = List(BigThing(thing,value), Bonus(thing), LittleThing(otherthing,value)) 
+0

Diese Klassen erweitern alle das Merkmal 'Thing', es macht mehr Sinn, den Rückgabetyp als' List [Thing] 'zu bezeichnen. Warum versuchst du das nicht in der REPL und siehst, was die Rückgabe ist, ohne den Typ anzugeben – Tanjin

+0

@Tanjin Ich habe meine Antwort aktualisiert. Schau mal. – Learner

Verwandte Themen