递归删除列表中的重复项

时间:2018-04-19 20:22:54

标签: scala recursion pattern-matching

我想使用与Scala匹配的模式

以递归方式从列表中删除重复项

这是我的输入

val xs = List(1,2,3,4,6,3,2,7,9,4)

尝试过的代码:

  def removeDuplicates(xs : List[Int]) : List[Int] = xs match {
  case Nil =>Nil
  case x::ys => { 
      if(ys.contains(x)){
      removeDuplicates(ys)
    } else {
        }
/// ???
  }
}

我被困在问号上,如何将我的结果添加到可变列表并返回它。

谢谢。

3 个答案:

答案 0 :(得分:3)

您需要跟踪当前状态:已经看到的元素使用集合(用于快速查找),以及正在构建的新列表:

@tailrec
def removeDuplicatesRec(
  remaining: List[Int], 
  seen: Set[Int], 
  acc: List[Int]
): List[Int] = remaining match {
  case Nil => acc
  case head :: tail => 
    if (!seen.contains(head)) removeDuplicatesRec(tail, seen + head, acc :+ head)
    else removeDuplicatesRec(tail, seen, acc)
}

def removeDuplicates(xs: List[Int]): List[Int] =
  removeDuplicatesRec(xs, Set.empty, List.empty)

答案 1 :(得分:3)

你很亲密:

 def removeDuplicates(xs : List[Int]) : List[Int] = xs match {
  case Nil => Nil
  case x::ys => if (ys.contains (x)) removeDuplicates (ys) else
      x :: removeDuplicates (ys)
 }

scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res143: List[Int] = List(1, 6, 3, 2, 7, 9, 4)

虽然这是一个简短的解决方案,但它不是尾递归的,因此容易受到堆栈溢出的影响 - 而Jean Logearts解决方案可以解决这个问题。

这是一个带内部函数的替代解决方案,也是tailrecursive:

def removeDuplicates (xsOuter : List[Int]) : List[Int] = {

  @annotation.tailrec
  def removeDuplicates (xs: List[Int], collected: List[Int]) : List[Int] = xs match {
    case Nil => collected
    case x :: ys => if (collected.contains (x)) removeDuplicates (ys, collected) else
      removeDuplicates (ys, x :: collected)
  }

  removeDuplicates (xsOuter, Nil)
}

scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res151: List[Int] = List(9, 7, 6, 4, 3, 2, 1)

偏向第一个元素,但结果反转,如果重要的话,可以通过在Nil情况下返回collected.reverse来轻松纠正。

外部函数为作业提供了一个简单的单参数接口,因此他不需要提供一个空列表。

请注意,该解决方案正在为类型注释而哭泣,因为它根本不依赖于Int类型的List元素:

scala> def removeDuplicates [A] (xsOuter : List[A]) : List[A] = {
     | 
     |   @annotation.tailrec
     |   def removeDuplicates (xs: List[A], collected: List[A]) : List[A] = xs match {
     |     case Nil => collected
     |     case x :: ys => if (collected.contains (x)) removeDuplicates (ys, collected) else
     |       removeDuplicates (ys, x :: collected)
     |   }
     | 
     |   removeDuplicates (xsOuter, Nil)
     | }
removeDuplicates: [A](xsOuter: List[A])List[A]

scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res152: List[Int] = List(9, 7, 6, 4, 3, 2, 1)

答案 2 :(得分:1)

这是使用内部函数和尾递归的经典方法。对于小型列表,尾部递归可能不是必需的,但我更容易理解。

  def removeDuplicates(xs : List[Int]) : List[Int] =  {
    @scala.annotation.tailrec
    def accumulator(xs: List[Int], acc: List[Int]):List[Int] = xs match {
      case Nil => acc
      case h::t if(!acc.contains(h)) => accumulator(t, h :: acc)
      case h::t if(acc.contains(h)) =>  accumulator(t, acc)
    }
    accumulator(xs, List[Int]())
  }

scala> removeDuplicates(List(1,2,3,4,6,3,2,7,9,4))
res16: List[Int] = List(9, 7, 6, 4, 3, 2, 1)

当然,distinct是首选方法,但这是一个很好的练习。 distinct可用于验证您的解决方案。

scala> List(1,2,3,4,6,3,2,7,9,4).distinct == removeDuplicates(List(1,2,3,4,6,3,2,7,9,4)).sorted
res21: Boolean = true