将第一个元素有条件地放入Scala中



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

给定列表:

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)

是否有现有功能?

我也认为模式匹配是可读性和性能的最佳选择(我测试了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)

,不,为此没有简单的内置功能。

如果您只想有条件地删除第一个元素,那么正如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
}

将明确将信息添加到您的元素中。

示例: 如何按条件下降并限制从左到右的数量?

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。

修改条件在合适的尺寸上您可以选择在收藏集内的下降条件到达多远。

这是一个广义变体(降至匹配谓词的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)

您可以用索引将列表缩小:

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
}

,但正如保罗所提到的,它将不必要地在整个列表中迭代。

这是一个不错的选择,如果您想根据过滤器删除第一个元素,但值不是首先。

def dropFirstElement( seq: Seq[Int], filterValue: Int ): Seq[Int] = {
  seq.headOption match {
    case None => seq
    case Some( `filterValue` ) => seq.tail
    case Some( value ) => value +: dropFirstElement( seq.tail, filterValue )
  }
}

最新更新