首页 文章

识别Scala序列中的连续间隔

提问于
浏览
3

假设我有一个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 回答

  • 4

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

    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)
    

    生产环境 :

    List(Interval(0,1), Interval(1,2), Interval(2,4), Interval(4,6))
    List(Interval(7,9), Interval(9,10))
    List(Interval(11,14))
    List(Interval(15,20), Interval(20,24))
    

    编辑:

    替代使用模式匹配:

    intervals.foldLeft(Seq[Seq[Interval]]()){
        case (Seq(Seq()), i) => Seq(Seq(i))
        case (h :: tail, i) if h.head.b == i.a => (i +: h) +: tail
        case (acc, i) => Seq(i) +: acc
    }.map(_.reverse).reverse.foreach(println)
    
  • 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))
    

相关问题