List 如何删除Scala中某个元素之前的重复整数

List 如何删除Scala中某个元素之前的重复整数,list,scala,filter,functional-programming,scala-collections,List,Scala,Filter,Functional Programming,Scala Collections,我有一个列表,在索引之前可以有一些我不需要的数字。例如: val tempList: List[Any] = List(0,0,0,0,0,3,.,5,0,2,5) 我如何才能删除3之前的所有0而不过滤掉3之后的0?您可以使用dropWhile。假设要删除1之前的所有内容: scala> val l = List(0, 0, 0, 0, 1, 2, 0) l: List[Int] = List(0, 0, 0, 0, 1, 2, 0) scala> l.dropWhile(_ =

我有一个列表,在索引之前可以有一些我不需要的数字。例如:

val tempList: List[Any] = List(0,0,0,0,0,3,.,5,0,2,5)

我如何才能删除3之前的所有0而不过滤掉3之后的0?

您可以使用
dropWhile
。假设要删除1之前的所有内容:

scala> val l = List(0, 0, 0, 0, 1, 2, 0)
l: List[Int] = List(0, 0, 0, 0, 1, 2, 0)

scala> l.dropWhile(_ == 0)
res1: List[Int] = List(1, 2, 0)

这可以通过
foldLeft
来完成,但在这种情况下,我会得到一个递归例程:

def remove(list: List[Any]): List[Any] = {
  def loop(rem: List[Any], res: List[Any]): List[Any] =
    rem match {
      case Nil =>
        res
      case 0 :: tail =>
        loop(tail, res)
      case 3 :: _ =>
        res ++ rem
      case x :: tail =>
        loop(tail, res :+ x)
      }

  loop(list, Nil)
}

remove(List(0,0,0,0,0,3,".",5,0,2,5))
// List(3, ., 5, 0, 2, 5)
请注意,这对于长列表来说并不有效,因为在长列表中添加到
列表的尾部会非常慢

此外,如注释中所述,如果可能,您应该避免使用
任何
,并使用更具体的类型


[由于@MikhailIonkin的简化]

您需要做的是在
dropWhile
上做一个扭曲,我会在
过滤时调用它

利用集合API的一个简单解决方案如下:

def filterWhile[A](
    list: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): List[A] = {
  val (toFilter, unfiltered) = list.span(whileP)
  toFilter.filter(filterP) ++ unfiltered
}
def test[A](
    input: List[A],
    expected: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): Unit =
  assert(
    filterWhile(input)(filterP, whileP) == expected,
    s"input: $input, expected: $expected, got: ${filterWhile(input)(filterP, whileP)}"
  )

test(
  input = List(0, 0, 0, 0, 0, 3, '.', 5, 0, 2, 5),
  expected = List(3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)

test(
  input = List(0, 0, 0, 1, 0, 3, '.', 5, 0, 2, 5),
  expected = List(1, 3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)

test(
  input = List(1, 2, 3, 4),
  expected = List(1, 2, 3, 4)
)(filterP = _ < 5, whileP = _ < 5)
您可以使用此代码,并进行两个测试以验证其是否按预期工作,如下所示:

def filterWhile[A](
    list: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): List[A] = {
  val (toFilter, unfiltered) = list.span(whileP)
  toFilter.filter(filterP) ++ unfiltered
}
def test[A](
    input: List[A],
    expected: List[A]
)(filterP: A => Boolean, whileP: A => Boolean): Unit =
  assert(
    filterWhile(input)(filterP, whileP) == expected,
    s"input: $input, expected: $expected, got: ${filterWhile(input)(filterP, whileP)}"
  )

test(
  input = List(0, 0, 0, 0, 0, 3, '.', 5, 0, 2, 5),
  expected = List(3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)

test(
  input = List(0, 0, 0, 1, 0, 3, '.', 5, 0, 2, 5),
  expected = List(1, 3, '.', 5, 0, 2, 5)
)(filterP = _ != 0, whileP = _ != 3)

test(
  input = List(1, 2, 3, 4),
  expected = List(1, 2, 3, 4)
)(filterP = _ < 5, whileP = _ < 5)

其中第一个谓词表示如何过滤,第二个谓词定义“while”子句。我选择将谓词顺序与函数名对齐(它首先显示“filter”,然后是“while”),但可以根据您的偏好进行调整。无论如何,在这里使用命名参数可能是一件好事。

结合列表上的现有函数,我想到了:

def filterUntil[A](list: List[A], filter: A => Boolean, cond: A => Boolean): List[A] = {
    list.takeWhile(cond).filter(filter) ++ list.dropWhile(cond)
}

这会产生与@stefanobaghino的答案几乎相同的结果。

任何问题都是代码气味,最好重新设计您的问题以避免它。使用
列表(0,1,0,3,0)
的结果应该是什么?它是
List(1,0,3,0)
还是
List(1,3,0)
还是其他什么?我认为这应该返回
List(1,2)
而不是
List(1,2,0)
,因为任务是“删除3之前的所有0”,而且因为您的示例数据没有表示所有0的3。这太复杂了。Scala是为编写简单代码而创建的。这个例子正好相反。此代码还使用
Any
作为参数类型。通常情况下,这是一个坏消息practice@MikhailIonkin如果你有一个更简单的解决方案,请张贴。答案使用了
Any
,因为问题使用了
Any
,我在回答中明确地说这是个坏主意。例如,你可以简化
(x:Int)::tail if x==0
0::tail
。另外,我认为最好重命名
remove
函数并重命名
循环的参数。