Kotlin在获得最大值最佳方法之前过滤列表?



如果你有一个对象列表对象对象(类别,值),并希望得到最大值排除一些类别,你可以使用这样的东西:

val max = objects.filter { it.category.name != xy }.maxByOrNull { it.value }

但是如果我理解正确的话,它使用了2个迭代器,那么是否会有一个只使用一个迭代器的性能更高的版本呢?

正确。此代码将首先遍历整个列表以过滤结果,然后再次查找最大值。

我将在下面详细介绍一些替代方案,但是,总的来说,如果没有很好的理由,我建议不要使用它们。性能上的好处通常是微不足道的——花时间确保代码清晰和经过良好测试将是更好的投资。我建议你坚持使用现有的代码。

例子这是你的代码的可执行版本。

fun main() {
val items = listOf(
MyData("shoes", 1),
MyData("shoes", 22),
MyData("shoes", 33),
MyData("car", 555),
)
val max = items
.filter {
println("  filter $it")
it.categoryName == "shoes"
}.maxByOrNull {
println("  maxByOrNull $it")
it.value
}
println("nresult: $max")
}

有两个迭代,每个迭代运行两次。

filter MyData(categoryName=shoes, value=1)
filter MyData(categoryName=shoes, value=22)
filter MyData(categoryName=shoes, value=33)
filter MyData(categoryName=car, value=555)
maxByOrNull MyData(categoryName=shoes, value=1)
maxByOrNull MyData(categoryName=shoes, value=22)
maxByOrNull MyData(categoryName=shoes, value=33)
result: MyData(categoryName=shoes, value=33)

序列在某些情况下,您可以使用序列来减少操作的数量。

val max2 = items
.asSequence()
.filter {
println("  filter $it")
it.categoryName == "shoes"
}.maxByOrNull {
println("  maxByOrNull $it")
it.value
}
println("nresult: $max2")

可以看到,操作顺序是不同的

filter MyData(categoryName=shoes, value=1)
filter MyData(categoryName=shoes, value=22)
maxByOrNull MyData(categoryName=shoes, value=1)
maxByOrNull MyData(categoryName=shoes, value=22)
filter MyData(categoryName=shoes, value=33)
maxByOrNull MyData(categoryName=shoes, value=33)
filter MyData(categoryName=car, value=555)
result: MyData(categoryName=shoes, value=33)

[S]序列可以避免构建中间步骤的结果,从而提高整个收集处理链的性能。

请注意,在这个小示例中,这些好处是不值得的。

然而,序列的惰性特性增加了一些开销,这在处理较小的集合或进行更简单的计算时可能是显著的。

结合操作在您的小示例中,您可以组合'filter'和'maxBy'操作

val max3 = items.maxByOrNull { data ->
when (data.categoryName) {
"shoes" -> data.value
"car"   -> -1
else    -> -1
}
}
println("nresult: $max3")
result: MyData(categoryName=shoes, value=33)

我希望大家清楚,这个解决方案不是立即可以理解的,并且有一些令人讨厌的边缘情况,这将是bug的主要来源。我不会详细说明这些问题,而是重申易用性、适应性和简单的代码通常比优化的代码更有价值!

最新更新