2016-04-28 85 views
1

我有以下要求,並希望轉換爲我想要的形式。給定輸入,我想根據每個類的id鍵對輸出進行一些調整。斯卡拉對變換Seq

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

任何人都有一些想法最好的辦法呢?謝謝。

回答

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

如果你改變你輸入的這個結構:

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])])] = { 
    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 
} 

底線是你只需要分組兩次。一天一天,另一天輪班。其餘的代碼只是轉換爲你想要的輸出格式。

轉化可以製成這樣的:

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

然後:

convert(input.map(flatten)) 
+1

我怎樣才能從我的輸入轉換到您指定的輸入? – ttt

+0

@ttt看到我編輯的答案 – fusion

+0

你也可以在convert方法中寫flatten,所以它會接受正確的格式並在裏面弄平。 – NieMaszNic

0

也許這樣的事情。代碼有點長,但適用於您的特定輸入。它也可以重構,因爲兩個部分函數幾乎相同。

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

這當然是SCALA,你可以在一個簡潔的方式把它寫:

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