在Scala中有条件地删除第一个元素?

时间:2017-05-02 22:15:25

标签: scala scala-collections

如果列表的第一个元素为零,则尝试删除它的第一个元素(不是真的,但是出于示例的目的)。

给出一个清单:

val ns = List(0, 1, 2)

删除第一个零可以通过将第一个匹配项删除为零来完成:

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

或者你可以删除所有不是零的东西。

List(0, 1, 2).filter(_ > 0)
res2: List[Int] = List(1, 2)

这些问题是当列表有多个零时。以前的解决方案不起作用,因为它们删除了太多的零:

List(0, 0, 1, 2, 0).filter(_ > 0)
res3: List[Int] = List(1, 2)

List(0, 0, 1, 2, 0).dropWhile(_ == 0)
res4: List[Int] = List(1, 2, 0)

这是否有现有功能?

5 个答案:

答案 0 :(得分:6)

我还认为模式匹配是可读性和性能的最佳选择(我测试过,OP中的模式匹配代码实际上比简单if ... else ...更好。)。

List(0, 0, 1, 2, 0) match { 
  case 0 :: xs => xs 
  case xs => xs
}
res10: List[Int] = List(0, 1, 2, 0)

而且,不,没有简单的内置功能。<​​/ p>

答案 1 :(得分:2)

如果您只想有条件地删除第一个元素,那么正如jwvh评论的那样,if/else理解可能是最简单的:

if (ns.nonEmpty && ns.head == 0) {
    ns.tail
} else {
    ns
}

然后你可以把它包装成一个函数。

您可以查找一个零的序列,然后删除它:

if (ns.startsWith(List(0))) {
  ns.drop(1)
} else {
  ns
}

也称为返回尾巴:

if (ns.startsWith(List(0))) {
  ns.tail
} else {
  ns
}

答案 2 :(得分:1)

一个简洁的通用解决方案将明确地向您的元素添加信息。

实施例:   如何按条件下降并从左到右限制金额?

List(0,0,0,1,2,2,3).zipWithIndex.dropWhile({case (elem,index) => elem == 0 && index < 2})

结果:

res0: List[(Int, Int)] = List((0,2), (1,3), (2,4), (2,5), (3,6))

您可以通过以下方式获取之前的演示文稿:

res0.map.{_._1}

要在N中执行所有操作,您可以使用延迟评估+ force方法。

List(0,0,0,1,2,2,3).view.zipWithIndex.dropWhile({case (elem,index) => elem == 0 && index < 2}).map {_._1}.force

这将基本上在一次迭代中对初始集合执行所有操作。有关Scala视图的详细信息,请参阅scaladoc

在正确的尺寸上修改您的条件,您可以选择放置条件在您的收藏中达到的距离。

答案 3 :(得分:1)

您可以使用索引压缩列表:

ns.zipWithIndex.filter( x =>( x._1 != 0 || x._2 != 0)).map(_._1)

以下是使用dropWhile的类似解决方案:

ns.zipWithIndex.dropWhile { 
  case (x, idx) => x == 0 && idx == 0
} map(_._1)

这也可能是一种理解

for {
  (x, idx) <- ns.zipWithIndex
  if (x != 0 || idx != 0) )
} yield {
  x
}

但正如保罗所说,它将不必要地遍历整个列表。

答案 4 :(得分:1)

这是一个广义变体(放到与谓词匹配的K个元素),它不处理列表的其余部分

  def dropWhileLimit[A](xs: List[A], f: A => Boolean, k: Int): List[A] = {
    if (k <= 0 || xs.isEmpty || !f(xs.head)) xs
    else dropWhileLimit(xs.tail, f, k - 1)
  } 

和一些测试用例:

dropWhileLimit(List(0,1,2,3,4), { x:Int => x == 0}, 1)
//> res0: List[Int] = List(1, 2, 3, 4)
dropWhileLimit(List(0,1,2,3,4), { x:Int => x == 0}, 2)
//> res1: List[Int] = List(1, 2, 3, 4)
dropWhileLimit(List(0,0,0,0,0), { x:Int => x == 0}, 1)
//> res2: List[Int] = List(0, 0, 0, 0)
dropWhileLimit(List(0,0,0,0,0), { x:Int => x == 0}, 3)
//> res3: List[Int] = List(0, 0)