我有以下要求,并希望转换为我想要的形式。根据输入,我想根据每个类的id键对输出做一些调整。
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())
)
任何人都有一些想法最好的方法吗?感谢。
答案 0 :(得分: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 :(得分: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 :(得分: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
}
}