识别Scala序列中的连续间隔

时间:2015-09-08 10:45:43

标签: scala

假设我有一个joda时间间隔序列:

Seq(
  Interval(00, 01),
  Interval(01, 02),
  Interval(02, 04),
  Interval(04, 06),
  Interval(07, 09), // continuous sequence is broken
  Interval(09, 10),
  Interval(11, 14), // continuous sequence is broken
  Interval(15, 20), // continuous sequence is broken
  Interval(20, 24)
)

我想查看这个序列,然后返回一个Seq [Seq [Interval]],它给出了连续的序列和非连续的序列,如:

Seq(
 Seq(Interval(00,01),Interval(01,02),Interval(02,04)Interval(04,06)),
 Seq(Interval(07,09),Interval(09,10)),
 Seq(Interval(11,14)),
 Seq(Interval(15,20),Interval(20,24))
)

我确实提出了一些递归,但它只是在找到一个非连续间隔之后切断了!有线索吗?

2 个答案:

答案 0 :(得分:4)

我相信这是foldLeft的候选人。随着时间的推移迭代建立所需结构的时间间隔。我发现将新项目添加到seq的头部更容易,因此最后使用了反向:

VSTO_LOGALERTS

产地:

LoadBehaviour

编辑:

替代使用模式匹配:

case class Interval(a: Int, b: Int)

val intervals = Seq(
    Interval(0, 1),
    Interval(1, 2),
    Interval(2, 4),
    Interval(4, 6),
    Interval(7, 9), // continuous sequence is broken
    Interval(9, 10),
    Interval(11, 14), // continuous sequence is broken
    Interval(15, 20), // continuous sequence is broken
    Interval(20, 24)
)

intervals.foldLeft(Seq[Seq[Interval]]()){(acc, i) => 
    if(acc.isEmpty){
        Seq(Seq(i))
    }else {
        if(acc.head.head.b == i.a) {
            (i +: acc.head) +: acc.tail
        } else {
            Seq(i) +: acc
        }
    }
}.map(_.reverse).reverse.foreach(println)

答案 1 :(得分:2)

我建议使用foldLeft和Vectors来累积结果。因为我发现它更具可读性,附加值而不是前置然后反转所有内容:

val testData = Seq(
  new Interval(0L, 1L),
  new Interval(1L, 2L),
  new Interval(2L, 4L),
  new Interval(4L, 6L),
  new Interval(7L, 9L), // continuous sequence is broken
  new Interval(9L, 10L),
  new Interval(11L, 14L), // continuous sequence is broken
  new Interval(15L, 20L), // continuous sequence is broken
  new Interval(20L, 24L)
)

val resultVector = testData.foldLeft(Vector.empty[Vector[Interval]]) {
  case (Vector(), current) => 
      Vector(Vector(current))
    case (init :+ last, current) if last.last.getEndMillis == current.getStartMillis =>
      init :+ (last :+ current)
    case (result, current) =>
      result :+ Vector(current)
}

为了使结果更具可读性,我添加了以下内容:

val readable = resultVector.map(_.map(interv => s"(${interv.getStartMillis} -> ${interv.getEndMillis})")).mkString("\n")

输出是:

readable: String = Vector((0 -> 1), (1 -> 2), (2 -> 4), (4 -> 6))
  Vector((7 -> 9), (9 -> 10))
  Vector((11 -> 14))
  Vector((15 -> 20), (20 -> 24))