将列表元素的连续重复项打包到Scala中的子列表中

时间:2019-01-15 03:41:14

标签: scala functional-programming

我在数据库中看到了一个与我的问题类似的问题,但这与我对代码的怀疑无关。我正在看下面的代码,因为我听不懂res.last.head!=h而陷入困境。我搜索了Scala的文档,但找不到_.last.head

  def _pack(res: List[List[A]], rem: List[A]):List[List[A]] = rem match {
    case Nil => res
    case h::tail if (res.isEmpty || res.last.head != h) => _pack(res:::List(List(h)), tail)
    case h::tail => _pack(res.init:::List(res.last:::List(h)), tail)
  }
  _pack(List(),l)
}
println(pack(List(1,1,2,3,3)))

1 个答案:

答案 0 :(得分:2)

我不确定您在那里遇到什么麻烦。您可以在List[A] ScalaDoc中找到它们。

List[A]是一个集合,内部存储为单个链接列表,每个节点(Cons)的head类型为Atail输入List[A]

List[A].last只是返回名称中所建议的列表中的最后一个元素(注意:这效率很低,因为它需要从头开始遍历整个列表)。现在,由于res的类型为List[List[A]],因此res.last的类型为List[A]List[A].head是列表中的第一个元素。

总结res.last.head是列表List中存储的最后res的第一个元素。


  

为什么有两个带有h::tail的case语句。

您需要详细了解Pattern matching in Scala,尤其是有关“后卫”的知识。 match / case中的代码可以重写为:

if (rem == Nil)
    res // first case
else {
  val h = rem.head
  val tail = rem.tail
  if (res.isEmpty || res.last.head != h)
     _pack(res:::List(List(h)), tail) // second case
  else
     _pack(res.init:::List(res.last:::List(h)), tail) // last case
}

换句话说,代码首先检查rem是否已经为空,如果为true,则退出。如果rem不为空,我们取其headh),现在我们可以选择:h是否匹配列表中的前一个元素。 if是第一种情况的守护者,没有if的最后一种情况充当else分支。