Scala:Seq [T]元素的功能聚合=> Seq [Seq [T]](保留顺序)

bin*_*ADa 5 collections functional-programming scala

我想在序列中聚合兼容元素,即将a转换Seq[T]Seq[Seq[T]]每个子序列中的元素彼此兼容的同时保留原始seq顺序,例如从

case class X(i: Int, n: Int) {
  def canJoin(that: X): Boolean = this.n == that.n
  override val toString = i + "." + n
}
val xs = Seq(X(1, 1), X(2, 3), X(3, 3), X(4, 3), X(5, 1), X(6, 2), X(7, 2), X(8, 1))
/* xs = List(1.1, 2.3, 3.3, 4.3, 5.1, 6.2, 7.2, 8.1) */
Run Code Online (Sandbox Code Playgroud)

想得到

val js = join(xs)
/* js = List(List(1.1), List(2.3, 3.3, 4.3), List(5.1), List(6.2, 7.2), List(8.1)) */
Run Code Online (Sandbox Code Playgroud)

我试图以功能的方式做到这一点,但我中途陷入困境:

做一个while循环

def split(seq: Seq[X]): (Seq[X], Seq[X]) = seq.span(_ canJoin seq.head)
def join(seq: Seq[X]): Seq[Seq[X]] = {
  var pp = Seq[Seq[X]]()
  var s = seq
  while (!s.isEmpty) {
    val (p, r) = split(s)
    pp :+= p
    s = r
  }
  pp
}
Run Code Online (Sandbox Code Playgroud)

随着split我的满意,但join似乎有点太长了.

在我看来,这是一项标准任务.这引出了我的问题:

  1. 集合库中是否有可以减少代码大小的函数?
  2. 或者可能有不同的方法来解决任务?特别是通过分区和折叠重写序列的另一种方法?

用尾递归替换while循环

def join(xs: Seq[X]): Seq[Seq[X]] = {
  @annotation.tailrec
  def jointr(pp: Seq[Seq[X]], rem: Seq[X]): Seq[Seq[X]] = {
    val (p, r) = split(rem)
    val pp2 = pp :+ p
    if (r.isEmpty) pp2 else jointr(pp2, r)
  }
  jointr(Seq(), xs)
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*itz 8

def join(seq: Seq[X]): Seq[Seq[X]] = {
  if (seq.isEmpty) return Seq()
  val (p,r) = split(seq)
  Seq(p) ++ join(r)
}
Run Code Online (Sandbox Code Playgroud)