【问题标题】:Transforming a scala list based on condition根据条件转换scala列表
【发布时间】:2019-10-30 13:42:48
【问题描述】:

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

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)

【问题讨论】:

    标签: scala scala-collections


    【解决方案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)
    

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2015-11-30
        • 2019-06-25
        • 2013-01-07
        • 2018-07-11
        • 1970-01-01
        • 1970-01-01
        • 2017-05-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多