2016-04-28 6 views
1

У меня есть следующие требования и вы хотите преобразовать в форму, которую я хочу. Учитывая ввод, я хочу сделать некоторое преобразование в вывод на основе ключа id каждого класса.Scala 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

вы также можете написать flatten в методе convert, чтобы он принял правильный формат и сделал сглаживание внутри. – 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 
    } 
} 
Смежные вопросы