如何从另一个列表中删除一个列表的每个实例?

How do you remove every instance of a list from another list?

我有一个列表

val l = List(1,2,3,2,6,4,2,3,4,2,1,3,6,3,2)

我想删除特定序列的每个实例,例如 (2,3)

所以期望的输出是...

List(1,2,6,4,4,2,1,3,6,3,2)

在 Scala 中,easiest/most 惯用的方法是什么?

到目前为止我已经尝试过这样做了..

l.sliding(2).filter{ _!=List(2,3) }

但后来我不知道从那里开始,这让我怀疑我是否走在正确的轨道上。

def stripFrom[A](lst: List[A], x: List[A]): List[A] =
  if (lst.containsSlice(x) && x.length > 0)
    stripFrom(lst.patch(lst.indexOfSlice(x), List(), x.length), x)
  else lst

概念验证:

scala> stripFrom(List(1,2,3,2,6,4,2,3,4,2,1,3,6,3,2), List(2,3))
res3: List[Int] = List(1, 2, 6, 4, 4, 2, 1, 3, 6, 3, 2)

scala> stripFrom(List(1,2,3,2,6,4,2,3,4,2,1,3,6,3,2), List(4,2))
res4: List[Int] = List(1, 2, 3, 2, 6, 3, 1, 3, 6, 3, 2)

scala> stripFrom(List(1,2,3,2,6,4,2,3,4,2,1,3,6,3,2), List(4,2,3,4))
res5: List[Int] = List(1, 2, 3, 2, 6, 2, 1, 3, 6, 3, 2)

scala> stripFrom(List(1,2,3,2,6,4,2,3,4,2,1,3,6,3,2), List(2))
res6: List[Int] = List(1, 3, 6, 4, 3, 4, 1, 3, 6, 3)

您可以递归地遍历列表,一次消耗一个列表头部的元素,并将所需的元素累积到结果列表中,同时丢弃匹​​配的不需要的序列。一个简单的尾递归示例可以像这样工作:

@annotation.tailrec
def filterList[A](list: List[A], acc: List[A] = Nil): List[A] = list match {
    case 2 :: 3 :: tail => filterList(tail, acc)
    case head :: tail => filterList(tail, head :: acc)
    case Nil => acc.reverse
}

scala> val l = List(1,2,3,2,6,4,2,3,4,2,1,3,6,3,2)
scala> filterList(l)
res0: List[Int] = List(1, 2, 6, 4, 4, 2, 1, 3, 6, 3, 2)

或者更一般地说,您可以使用 startsWith 检查 List 的当前迭代是否以您要删除的序列开始。

@annotation.tailrec
def filterList[A](list: List[A], subList: List[A], acc: List[A] = Nil): List[A] = list match {
    case l if(list startsWith subList) => filterList(l.drop(subList.length), subList, acc)
    case head :: tail => filterList(tail, subList, head :: acc)
    case Nil => acc.reverse
}

scala> filterList(l, List(2, 3))
res4: List[Int] = List(1, 2, 6, 4, 4, 2, 1, 3, 6, 3, 2)

如果性能有问题,您可以使 acc 可变。