我有一个序列val as = Seq[A]
中的对象列表。 A
看起来像这样:
import java.time.Instant
case class A(t: String, start: Instant, end: Instant)
现在,我想有条件地合并as
中的元素:每当两个后续项目(即直接相邻)a1
和a2
的{{1}}值相同时,它们应该合并成这样:
t
请注意,不能直接在其他项目上直接继承的项目绝对不能合并,例如:
object A {
def merge(a1: A, a2: A): A = {
require(a1.t == a2.t)
A(a1.t, a1.start, a2.end)
}
}
但是:
Seq(A("a", ...), A("a", ...), A("b", ...), ...) // -> merge the first two elements
有一个similar question on SO,但它合并了多个列表,因此不适用于我的情况。
我的第一种方法:
Seq(A("a", ...), A("b", ...), A("a", ...), ...) // -> do not merge any elements
尽管有多个缺陷。除此之外,我不确定在第二种情况下该怎么做(即保持as.zip(as.tail)
.map {
case (a1: A, a2: A) if (a1.t == a2.t) => merge(a1, a2)
case (a1: A, a2: A) => ???
}
和a1
不变),这也不适用于多个应合并的后续元素。
我的直觉将我引向a2
:
foldLeft
这解决了多个需要合并的后续元素的问题。但是,它将尝试合并所有as.foldLeft(???)(A.merge)
实现中无法实现的元素。
我可以改编merge
,但我仍不清楚如何:如果为merge()
,则结果类型应为新的a1.t == a2.t
,否则应“返回” {{1 }}和A
。
我对后一种想法的处理方法是将这些方法添加到类a1
中:
a2
但是在这里,我不能真正在序列A
的{{1}}调用中使用def merge(that: A): (A, Option[A]) =
if (this.t == that.t)
(A(t, this.start, that.end), None)
else
(this, Some(that))
的输出。
两种方法中的根本问题是:我应该如何处理这样的事实:有时候(当merge()
匹配时,我想向新序列中添加一个新的foldLeft()
,而在另一个序列中情况下,我需要添加两个元素。
我对如何以函数式编程方式解决此问题感到迷茫。
当然,我可以遍历as
的列表,将应合并的内容存储在新的数据结构中,然后再次生成。有更好的方法吗?
答案 0 :(得分:3)
基于RoberMP的答案,如果您使用foldRight
来构建List
,则可以将模式匹配与cons运算符配合使用,该模式匹配应比尾部操作更有效:
def merge(sequence: Seq[A]) = {
sequence.foldRight(List.empty[A]) {
case (A(t1, x, _), A(t2, _, y) :: list) if t1 == t2 => A(t1, x, y) :: list
case (other, list) => other :: list
}
}
这从右到左起作用,因此我们可以在匹配中使用::
,但仍应具有预期的输出。
答案 1 :(得分:0)
我认为foldLeft是正确的方法,类似(未测试):
TheTableName
INT_ASTIK_EAS
INT_BLD_PST
ER_ASTTOM_ASTIK
etc...
请注意,这里有很多尾部操作,所以不知道Seq是否是此用例的更好集合类型