根据条件转换 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
的相反顺序组装的,以实现大规模性能。
我有一个排序的元组列表(按行号的最后一个元素排序)
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
的相反顺序组装的,以实现大规模性能。