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

在Scala中将连续重复的列表元素打包到子列表中,scala,functional-programming,Scala,Functional Programming,我在数据库中看到了一个类似于我的问题,但与我对代码的怀疑无关。我正在浏览下面的代码,我被卡住了,因为我不理解res.last.head=h?我搜索了Scala的文档,但找不到什么是\uu.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

我在数据库中看到了一个类似于我的问题,但与我对代码的怀疑无关。我正在浏览下面的代码,我被卡住了,因为我不理解
res.last.head=h
?我搜索了Scala的文档,但找不到什么是
\uu.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)))

我不确定你在那里遇到了什么麻烦。您可以在中找到这两者

List[A]
是一个在内部存储为单个链表的集合,每个节点(
Cons
)具有
A
类型的
,以及
List[A]
类型的

List[A].last
只返回列表中的最后一个元素(注意:这是非常低效的,因为它需要从一开始遍历整个列表)。现在由于
res
属于
List[A]
类型,因此
res.last
属于
List[A]
类型<代码>列表[A]。头是列表中的第一个元素

总之,
res.last.head
是存储在列表列表
res
中的最后一个
列表的第一个元素


为什么有两个带有
h::tail
的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
是否已为空,如果为真则退出。如果
rem
不是空的,我们取它的
头(
h
),现在我们有一个选择:这个
h
是否匹配列表中的前一个元素。这个
如果
是第一个案例,没有
如果
的最后一个案例作为
其他
分支。

我不知道你有什么问题。您可以在中找到这两者

List[A]
是一个在内部存储为单个链表的集合,每个节点(
Cons
)具有
A
类型的
,以及
List[A]
类型的

List[A].last
只返回列表中的最后一个元素(注意:这是非常低效的,因为它需要从一开始遍历整个列表)。现在由于
res
属于
List[A]
类型,因此
res.last
属于
List[A]
类型<代码>列表[A]。头是列表中的第一个元素

总之,
res.last.head
是存储在列表列表
res
中的最后一个
列表的第一个元素


为什么有两个带有
h::tail
的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
是否已为空,如果为真则退出。如果
rem
不是空的,我们取它的
头(
h
),现在我们有一个选择:这个
h
是否匹配列表中的前一个元素。此
if
是第一个案例,没有
if
的最后一个案例作为
else
分支。

好的。我现在明白了,但是为什么有两个带有h::tail的case语句。我确实理解第一个h::tail,但第二个case语句有什么用?@user2708013,我已经更新了我的答案。希望有帮助,好的。我现在明白了,但是为什么有两个带有h::tail的case语句。我确实理解第一个h::tail,但第二个case语句有什么用?@user2708013,我已经更新了我的答案。希望有帮助。请注意,这是相当糟糕的代码和非常低效的,所以不要从中学习坏习惯!你能再解释一下吗?我正处于学习阶段简单地说,
last
init
需要搜索整个列表,并为列表中的每个元素调用,因此性能是
O(n^2)
,随着输入时间的延长,性能会变得非常慢。反向构建列表,然后在返回结果之前反向生成结果,速度要快得多。您还应该避免使用
last
head
,因为它们在空列表中失败,您更喜欢
lastpoption
headOption
。请注意,这是一个相当糟糕的代码,效率非常低,因此不要从中学习坏习惯!你能再解释一下吗?我正处于学习阶段简单地说,
last
init
需要搜索整个列表,并为列表中的每个元素调用,因此性能是
O(n^2)
,随着输入时间的延长,性能会变得非常慢。反向构建列表,然后在返回结果之前反向生成结果,速度要快得多。您还应该避免使用
last
head
,因为它们在空列表中失败,您更喜欢
lastpoption
headOption