作为家庭作业,我必须编写一个能够从列表中删除重复项的函数。它应该是递归的并且具有模式匹配。我不允许使用head,tail,contains等列表函数 对于排序列表,我提出了这个解决方案:
ReadCommited
如何处理未排序的列表?
答案 0 :(得分:6)
我不会为你做功课,但希望,这会有所帮助。
hd :: remove(tl)
:你必须调用递归调用,然后将hd
添加到其结果中。 然后部分打破了尾递归的想法,因为jvm必须在堆栈上记住递归调用完成后返回的位置。 通常通过将递归作为参数传递函数的最终结果来避免这种情况:
def remove(u: List[Int], result: List[Int] = Nil): List[Int] = u match {
case Nil => result
case a :: b :: tail if a == b => remove(b :: tail, result)
case head :: tail => remove(tail, head :: result)
}
(注意,这里的递归调用都处于尾部位置 - 在调用返回后没有什么可做的,所以在调用递归之前可以从堆栈中清除前一个条目。)
您需要另一个递归函数 - contains
- 它告诉一个给定元素是否包含在列表中。完成后,只需将上面的第二个case
子句替换为
case head :: tail if contains(head, result) => remove(tail, result)
你的工作已经完成!
reverse
(将case Nil => result
替换为case Nil => result.reverse
)...如果您不被允许在这里使用.reverse
,对你来说这将是另一个很好的练习。你如何递归地反转列表(尾部)?答案 1 :(得分:1)
我可能会首先对列表进行排序,以便我们可以应用O(n)复杂度模式匹配方法,但是为了保持您需要的顺序索引列表以便以后可以恢复订单,这可以使用zipWithIndex
方法完成。此外,由于数据类型从List[Int]
更改为List[(Int, Int)]
,因此您需要在原始数据类型中定义另一个递归删除函数:
def remove(u: List[Int]): List[Int] = {
val sortedU = u.zipWithIndex.sortBy{ case (x, y) => x}
def removeRec(su: List[(Int, Int)]): List[(Int, Int)] = {
su match {
case Nil => su
case hd :: Nil => su
case hd :: hd2 :: tail => {
if (hd._1 == hd2._1) removeRec(hd2 :: tail)
else hd :: removeRec(hd2 :: tail)
}
}
}
removeRec(sortedU).sortBy{case (x, y) => y}.map{ case (x, y) => x}
}
val lst = List(1,2,3,1,3,3)
remove(lst)
// res51: List[Int] = List(2, 1, 3)
注意:这遵循OP的模式,而不是尾递归。如果你想要一个尾递归版本,你可以按照@Dima的好解释。