根据条件转换 Scala 列表

Transforming a scala list based on condition

我有一个排序的元组列表(按行号的最后一个元素排序)

val x = List(
            ("taskENTER_CRITICAL", 1443),
            ("taskEXIT_CRITICAL", 1492),
            ("taskEXIT_CRITICAL", 1510),
            ("taskEXIT_CRITICAL", 1528),
            ("taskENTER_CRITICAL", 1551),
            ("taskEXIT_CRITICAL", 1555),
            ("taskENTER_CRITICAL", 1602),
            ("taskEXIT_CRITICAL", 1614)
          )

我需要将其转换为

 ("taskENTER_CRITICAL", 1443),
 ("taskEXIT_CRITICAL", 1528),
 ("taskENTER_CRITICAL", 1551),
 ("taskEXIT_CRITICAL", 1555),
 ("taskENTER_CRITICAL", 1602),
 ("taskEXIT_CRITICAL", 1614)

根据迭代列表的条件去掉两个元素,只在遇到列表中的下一个ENTER时才选择上一个EXIT

最后要把它改成牛肚

("CS", 1443, 1528)
("CS", 1551, 1555)
("CS", 1602, 1614)

.foldLeft 是要走的路,基本上是累加器模式。您需要知道在现有列表之上创建一个新列表而不改变现有列表(即 :+),还需要使用 .copy

更新数据
val data = List(
  ("taskENTER_CRITICAL", 1443),
  ("taskEXIT_CRITICAL", 1492),
  ("taskEXIT_CRITICAL", 1510),
  ("taskEXIT_CRITICAL", 1528),
  ("taskENTER_CRITICAL", 1551),
  ("taskEXIT_CRITICAL", 1555),
  ("taskENTER_CRITICAL", 1602),
  ("taskEXIT_CRITICAL", 1614)
)

val enterExits =
  data.foldLeft((List.empty[(String, Int)], Option.empty[(String, Int)])) {
    case ((state, previousSignal), signal) =>
      if (previousSignal.exists(_._1.contains("EXIT")) && signal._1.contains("EXIT")) {
        (state.dropRight(1) :+ signal, Some(signal))
      } else {
        (state :+ signal, Some(signal))
      }
  }

val triple =
  enterExits._1
    .foldLeft(
      (List.empty[(String, Int, Int)], Option.empty[(String, Int, Int)])) {
      case ((state, accSignal), signal) =>
        if (signal._1.contains("ENTER")) {
          (state, Some(("CS", signal._2, 0)))
        } else {
          val enterExt = accSignal.map(elem => elem.copy(_3 = signal._2))
          (state :+ enterExt.get, Option.empty)
        }
    }._1

triple.foreach { ee =>
  println(ee)
}

输出:

(CS,1443,1528)
(CS,1551,1555)
(CS,1602,1614)

注意:上面的答案假设每个 Enter.

总是等价的 Exit

运行 代码位于:https://scastie.scala-lang.org/prayagupd/3670tsL0Qf683QFAQ9nLIQ

这是一种使用 foldLeft 和 Tuple-type 累加器的方法,累加器携带当前字符串元素以在下一次迭代中进行相等性检查,然后使用 grouped 进行最终转换:

val list = List(
  ("taskENTER_CRITICAL", 1443),
  ("taskEXIT_CRITICAL", 1492),
  ("taskEXIT_CRITICAL", 1510),
  ("taskEXIT_CRITICAL", 1528),
  ("taskENTER_CRITICAL", 1551),
  ("taskEXIT_CRITICAL", 1555),
  ("taskENTER_CRITICAL", 1602),
  ("taskEXIT_CRITICAL", 1614)
)

val list2 = list.foldLeft( (List[(String, Int)](), "") ){
  case ((l, sp), (s, i)) => s match {
    case "taskENTER_CRITICAL" => ((s, i) :: l, s)
    case "taskEXIT_CRITICAL" if s == sp => ((s, i) :: l.tail, s)
    case _ => ((s, i) :: l, s)
  }
}._1.reverse
// list2: List[(String, Int)] = List(
//   (taskENTER_CRITICAL,1443), (taskEXIT_CRITICAL,1528),
//   (taskENTER_CRITICAL,1551), (taskEXIT_CRITICAL,1555),
//   (taskENTER_CRITICAL,1602), (taskEXIT_CRITICAL,1614)
// )

list2.grouped(2).collect{ case List(a, b) => ("CS", a._2, b._2) }.toList
// res2: List[(String, Int, Int)] = List((CS,1443,1528), (CS,1551,1555), (CS,1602,1614))

请注意,在 foldLeft 之后需要反转列表元素,因为列表是按 ::tail 的相反顺序组装的,以实现大规模性能。