首页 > 解决方案 > 按一定百分比均匀过滤列表 - Kotlin/Java

问题描述

我正在寻找一种在 Kotlin/Java 中最有效的方法来过滤List一定百分比的元素,并且删除过滤的元素将以统一的方式应用于整个集合(即 - 要删除的元素跨越整个收集均匀);

例如

我想出了以下 Kotlin 扩展函数,它在百分比 < 50% 且集合很大时效果很好,但是当集合 >50% 时,这种方法就失败了,因为它只处理整数除法。

private fun <E> List<E>.filterDownBy(perc: Int): List<E> {
val distro = this.size / ((perc * this.size) / 100)
if (perc == 0 || distro >= this.size)
    return this
return this.filterIndexed { index, _ -> (index % distro) != 0 }

有没有更好的方法来做到这一点并且当百分比> 50%时也会起作用?

标签: javakotlincollections

解决方案


我认为标准库中没有太多帮助,但我想出了这种“手动”方法:

fun <T> List<T>.takeProportion(prop: Double): List<T> {
    if (prop < 0 || prop > 1)
        throw IllegalArgumentException("prop ($prop) must be between 0 and 1")
    val result = ArrayList<T>()
    var tally = 0.5
    for (i in this) {
        tally += prop
        if (tally >= 1.0) {
            result += i
            tally -= 1
        }
    }
    return result
}

它使用一种错误扩散方式来确保值在列表中均匀获取,并使用浮点数以便它可以平滑地处理从 0.0(给出一个空列表)到 1.0(获取每个元素)的任何比例。

(可能有一种仅使用整数算术的方法,但使用浮点可能更易于编码和理解。)

(您可能可以通过使用使其更具功能性filter(),但这并不合适,因为 lambda 必须使用和更新外部状态。)


推荐阅读