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
函数并重命名循环的参数。