scala - 如何删除Scala集合中的尾随元素?

标签 scala

假设我有一个看起来像这样的列表:

List(0,5,34,0,9,0,0,0)

我想结束的是:
List(0,5,34,0,9)

我要删除所有尾随的零。有没有一种方法,类似于:
list.trimRight(_ == 0)

会做到吗?我可以从头开始编写它,但是在我看来,这是std集合附带的东西吗?

我想出了:
list.take(list.lastIndexWhere(_ != 0) + 1)

有没有更好的方法?

最佳答案

如果你想知道哪个最优雅,那我会说

list.reverse.dropWhile(_ == 0).reverse

因为它只需要引用一次输入,并且意图很明确。

如果您想知道哪个是最有效的,则需要进行一些基准测试。结果(针对您的简短测试列表)可能会让您感到惊讶!
// Slowest
191 ns     dhg's EnhancedSeq
173 ns     user unknown's custom dropRight
 91 ns     andyczerwonka's take/lastIndexWhere
 85 ns     Rex's :\ (foldRight) -- see below
 60 ns     dhg / Daniel's reverse/dropWhile/reverse
 52 ns     Rex's customDropTrailingZeros -- see below
// Fastest

机器之间可能会有一些适度的差异,但是基本上,在这种情况下,花短名单对您没有帮助。如果 list 很长,情况可能会发生很大变化。

这是折叠版本(但是堆栈在大列表上溢出):
(list :\ list.take(0)){ (x,ys) => if (x==0 && ys.isEmpty) ys else x :: ys }

这是自定义版本(完全非通用-仅适用于此特定任务!):
@annotation.tailrec def customDropZeros(
  xs: List[Int],
  buffer: Array[Int] = new Array[Int](16),
  n: Int = 0
): List[Int] = {
  if (xs.isEmpty) {
    var ys = xs
    var m = n
    while (m>0 && buffer(m-1)==0) m -= 1
    var i = m-1
    while (i>=0) {
      ys = buffer(i) :: ys
      i -= 1
    }
    ys
  }
  else {
    val b2 = (
      if (n<buffer.length) buffer
      else java.util.Arrays.copyOf(buffer, buffer.length*2)
    )
    b2(n) = xs.head
    customDropZeros(xs.tail, b2, n+1)
  }
}

tl; dr

除非您有充分的理由,否则请使用reverse dropWhile reverse。它出奇地快和出奇地清晰。

关于scala - 如何删除Scala集合中的尾随元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10710954/

相关文章:

scala - Scala 中的 JavaConverters 和 JavaConversions 有什么区别?

scala - Scala RDD 不协变的解决方法

scala - Scala 插件缺少 NetBeans 8.2 外部执行基础 API

sql - 优化 Slick 生成的 SQL 查询

scala - Scala 有没有办法在不使用 if 嵌套的情况下转义多个 return 语句

java - Case 类导致 java.lang.ExceptionInInitializerError

mongodb - 如何使用ReactiveMongo指定replicaSet名称?

scala - F[_] 和 F[T] 在 Scala 中用于类型构造函数时的区别

scala - HashPartitioner 是如何工作的?

使用带有泛型类型接口(interface)的 Java 库时的 Scala 编译问题