根据条件转换scala列表

时间:2019-06-16 23:08:42

标签: scala scala-collections

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

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)

2 个答案:

答案 0 :(得分:2)

这是一种使用foldLeft和Tuple型累加器的方法,该累加器将当前字符串元素移到下一次迭代中以进行相等性检查,然后使用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组合在一起的,以实现大规模的性能。

答案 1 :(得分:1)

.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)

注意:上面的答案假设每个Exit总是有相等的Enter

https://scastie.scala-lang.org/prayagupd/3670tsL0Qf683QFAQ9nLIQ

上运行代码