有序列地合并项目

时间:2018-06-27 12:33:06

标签: scala functional-programming reduce

我有一个序列val as = Seq[A]中的对象列表。 A看起来像这样:

import java.time.Instant
case class A(t: String, start: Instant, end: Instant)

现在,我想有条件地合并as中的元素:每当两个后续项目(即直接相邻)a1a2的{​​{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的列表,将应合并的内容存储在新的数据结构中,然后再次生成。有更好的方法吗?

2 个答案:

答案 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是否是此用例的更好集合类型