2016-04-28 14 views
1

Ich habe die folgenden Anforderungen, und möchte in die Form, die ich will transformieren. Bei der Eingabe möchte ich eine gewisse Konversation zur Ausgabe basierend auf dem ID-Schlüssel jeder Klasse durchführen.Scala Seq der Paar-Transformation

case class Day(id: Int, name: String) 
case class Shift(id: Int, dayId: Int) 
case class Break(id: Int, shiftId: Int) 

val day1 = Day(1, "xx") 
val day2 = Day(2, "xx") 
val day3 = Day(3, "xx") 

val shift1 = Shift(1, 1) 
val shift2 = Shift(2, 1) 
val shift3 = Shift(3, 2) 

val break1 = Break(1, 1) 
val break2 = Break(2, 3) 

val input = Seq(
    ((day1, Some(shift1)), Some(break1)), 
    ((day1, Some(shift2)), None), 
    ((day2, Some(shift3)), Some(break2)), 
    ((day3, None), None) 
) 

def convert(input: Seq[((Day, Option[Shift]), Option[Break])]): Seq[(Day, Seq[(Shift, Seq[Break])])] = { 
    ??? 
} 

val output = Seq(
    (day1, Seq((shift1, Seq(break1)), (shift2, Seq()))), 
    (day2, Seq((shift3, Seq(break2)))), 
    (day3, Seq()) 
) 

Wer hat eine Idee den besten Weg, es zu tun? Vielen Dank.

Antwort

2
case class Day(id: Int, name: String) 
case class Shift(id: Int, dayId: Int) 
case class Break(id: Int, shiftId: Int) 

val day1 = Day(1, "xx") 
val day2 = Day(2, "xx") 
val day3 = Day(3, "xx") 

val shift1 = Shift(1, 1) 
val shift2 = Shift(2, 1) 
val shift3 = Shift(3, 2) 

val break1 = Break(1, 1) 
val break2 = Break(2, 3) 

val input = Seq(
    ((day1, Some(shift1)), Some(break1)), 
    ((day1, Some(shift2)), None), 
    ((day2, Some(shift3)), Some(break2)), 
    ((day2, None), None) 
) 

def convert(input: Seq[((Day, Option[Shift]), Option[Break])]): Seq[(Day, Seq[(Shift, Seq[Break])])] = { 
    input.groupBy(_._1._1).toSeq.map(d=>(d._1,d._2.groupBy(_._1._2).filter(_._1.isDefined).toSeq.map(s=>(s._1.get,s._2.flatMap(_._2))))) 
} 

val output = Seq(
    (day1, Seq((shift1, Seq(break1)), (shift2, Seq()))), 
    (day2, Seq((shift3, Seq(break2)))), 
    (day3, Seq()) 
) 
2

Wenn Sie die Struktur Ihrer Eingabe in das ändern:

val input = Seq(
    (day1, Some(shift1), Some(break1)), 
    (day1, Some(shift2), None), 
    (day2, Some(shift3), Some(break2)), 
    (day2, None, None) 
) 

(Sie die Verschachtelung der Tupel überspringen)

dann können Sie diese Funktion convert unten verwenden:

def convert(input: Seq[(Day, Option[Shift], Option[Break])]): Seq[(Day, Seq[(Shift, Seq[Break])])] = { 
    val a = input.groupBy(_._1).map { case (day, gr) => 
     (day, gr.collect { case (_, Some(shift), breakOpt) => 
       (shift, breakOpt) 
      }.groupBy(_._1).toSeq.map { case (shift, sq) => (shift, sq.flatMap(_._2))}) 
    } 
    a.toSeq 
} 

Die Quintessenz ist, dass Sie nur zweimal gruppieren müssen. Einmal mit Tag und einmal mit Schicht. Der Rest des Codes ist einfach eine Konvertierung in das gewünschte Ausgabeformat.

def flatten[A, B, C](t: ((A, B), C)) = (t._1._1, t._1._2, t._2) 

und dann:

convert(input.map(flatten)) 
+1

Wie kann ich umwandeln von meinem Eingang mit dem Eingang von Ihnen angegebenen? – ttt

+0

@ttt sehe meine bearbeitete Antwort – fusion

+0

Sie könnten auch flach in der Convert-Methode schreiben, so würde es das richtige Format akzeptieren und die flatten innerhalb machen. – NieMaszNic

0

Vielleicht so etwas

Die Umwandlung kann wie folgt vorgenommen werden. Der Code ist ein wenig lang, aber es funktioniert für Ihre spezifische Eingabe. Es kann auch umstrukturiert werden, weil zwei Teilfunktionen fast gleich sind.

case class Day(id: Int, name: String) 

case class Shift(id: Int, dayId: Int) 

case class Break(id: Int, shiftId: Int) 

val day1 = Day(1, "xx") 
val day2 = Day(2, "xx") 
val day3 = Day(3, "xx") 

val shift1 = Shift(1, 1) 
val shift2 = Shift(2, 1) 
val shift3 = Shift(3, 2) 

val break1 = Break(1, 1) 
val break2 = Break(2, 3) 

val input = Seq(
    ((day1, Some(shift1)), Some(break1)), 
    ((day1, Some(shift2)), None), 
    ((day2, Some(shift3)), Some(break2)), 
    ((day2, None), None) 
) 

type MyReturnType = (Day, Seq[(Shift, Seq[Break])]) 

def convert(input: Seq[((Day, Option[Shift]), Option[Break])]): Seq[MyReturnType] = { 
    input.foldLeft(Seq[MyReturnType]()) { 
    case (acc, ((day, Some(shift)), Some(break))) => 

     val findExistingDay = acc.find { case (d, _) => d == day } 
     val seqWithoutDay = acc.filter { case (d, _) => d != day } 


     val addNewElementIfDayExists = findExistingDay.map { case (d, seq) => 
     (d, seq :+(shift, Seq(break))) +: seqWithoutDay 
     } 

     val otherwiseCreateANewOne = addNewElementIfDayExists.getOrElse((day, Seq((shift, Seq(break)))) +: acc) 
     otherwiseCreateANewOne 

    case (acc, ((day, Some(shift)), None)) => 

     val findExistingDay = acc.find { case (d, _) => d == day } 
     val seqWithoutDay = acc.filter { case (d, _) => d != day } 


     val addNewElementIfDayExists = findExistingDay.map { case (d, seq) => 
     (d, seq :+(shift, Seq())) +: seqWithoutDay 
     } 

     val otherwiseCreateANewOne = addNewElementIfDayExists.getOrElse((day, Seq((shift, Seq()))) +: acc) 
     otherwiseCreateANewOne 

    case (acc, ((day, None), Some(break))) => 
     ??? //I don't know what should I do in this case, because you didn't provide an example 
    case (acc, ((day, None), None)) => 
     acc 
    } 
} 
val convertResult: Seq[MyReturnType] = convert(input) 

convertResult.foreach(println) 
/* result: 
(Day(2,xx),List((Shift(3,2),List(Break(2,3))))) 
(Day(1,xx),List((Shift(1,1),List(Break(1,1))), (Shift(2,1),List()))) 
res0: Unit =() 
*/ 

//if you need it in a specific order: 

convertResult.sortBy(_._1.id).foreach(println) 
/* result: 
(Day(1,xx),List((Shift(1,1),List(Break(1,1))), (Shift(2,1),List()))) 
(Day(2,xx),List((Shift(3,2),List(Break(2,3))))) 
res1: Unit =() 
*/ 

//if you also need an empty day3, then you have to somehow group the all days. Maybe like this:: 
val allDays = List(day1, day2, day3) 
val withEmptyDays: Seq[MyReturnType] = allDays.map(d => convertResult.find(_._1 == d).getOrElse((d, Seq()))) 
withEmptyDays.foreach(println) 
/* 
(Day(1,xx),List((Shift(1,1),List(Break(1,1))), (Shift(2,1),List()))) 
(Day(2,xx),List((Shift(3,2),List(Break(2,3))))) 
(Day(3,xx),List()) 
res2: Unit =() 
*/ 


val output = Seq(
    (day1, Seq((shift1, Seq(break1)), (shift2, Seq()))), 
    (day2, Seq((shift3, Seq(break2)))), 
    (day3, Seq()) 
) 

Natürlich ist das SCALA und Sie können es in prägnanter Weise schreiben:

def convert(input: Seq[((Day, Option[Shift]), Option[Break])]): Seq[(Day, Seq[(Shift, Seq[Break])])] = { 
    def helper(acc:Seq[(Day, Seq[(Shift, Seq[Break])])], day:Day, shift:Shift, breaks:Seq[Break]) = 
    acc.find(_._1 == day).map(a =>(a._1, a._2 :+ (shift, breaks)) +: acc.filter(_._1 != day)).getOrElse((day, Seq((shift, breaks))) +: acc) 
    input.foldLeft(Seq[(Day, Seq[(Shift, Seq[Break])])]()) { 
    case (acc, ((day, Some(shift)), Some(break))) => helper(acc, day, shift, Seq(break)) 
    case (acc, ((day, Some(shift)), None)) => helper(acc, day, shift, Seq()) 
    case (acc, ((day, None), Some(break))) => 
     ??? 
    case (acc, ((day, None), None)) => 
     acc 
    } 
}