Преобразование списка Scala на основе условия - PullRequest
0 голосов
/ 17 июня 2019

У меня есть отсортированный список кортежей (отсортированный по последнему элементу, который является белья)

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)

Два элемента удаляются в зависимости от условия итерации списка и выбора предыдущего ВЫХОДА только при обнаружении следующего ВВОДА в списке

Наконец-то нужно превратить это в шалость

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

Ответы [ 2 ]

2 голосов
/ 17 июня 2019

Вот один подход, использующий 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 голос
/ 17 июня 2019

.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 / praagagupd / 3670tsL0Qf683QFAQ9nLIQ

...