假设我有一个看起来像这样的列表:
List(0,5,34,0,9,0,0,0)
Run Code Online (Sandbox Code Playgroud)
我想最终得到的是:
List(0,5,34,0,9)
Run Code Online (Sandbox Code Playgroud)
我正在删除所有尾随的零.有没有一种方法,比如:
list.trimRight(_ == 0)
Run Code Online (Sandbox Code Playgroud)
会做到这一点?我可以从头开始编写它,但在我看来,这是std集合中的东西吗?
我提出了:
list.take(list.lastIndexWhere(_ != 0) + 1)
Run Code Online (Sandbox Code Playgroud)
有更好的方法吗?
Rex*_*err 12
如果你想知道哪个是最优雅的,那么我会说
list.reverse.dropWhile(_ == 0).reverse
Run Code Online (Sandbox Code Playgroud)
因为它只需要引用一次输入,意图非常明确.
如果您想知道哪个是最有效的,您需要做一些基准测试.结果(对于您的简短测试列表)可能会让您感到惊讶!
// 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
Run Code Online (Sandbox Code Playgroud)
可能存在一些适度的机器到机器的差异,但基本上这是一种情况,对于简短的列表,花哨并没有帮助你.很长的列表可能会发生很大的变化.
这是折叠版本(但是大型列表上的堆栈溢出):
(list :\ list.take(0)){ (x,ys) => if (x==0 && ys.isEmpty) ys else x :: ys }
Run Code Online (Sandbox Code Playgroud)
这是自定义版本(完全非通用 - 仅适用于此特定任务!):
@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)
}
}
Run Code Online (Sandbox Code Playgroud)
使用reverse dropWhile reverse除非你有充分的理由,否则.它出人意料地快速且令人惊讶地清晰.