我正在寻找一种在 Kotlin/Java 中最有效的方法,将List
过滤一定百分比,并且随着过滤元素的删除将以统一的方式应用于整个集合(即 - 要删除的元素均匀地跨越整个集合(;
例如
- 按 50%
[0,1,2,3,4,5,6,7,8,9] = [0,2,4,6,8]
筛选以下内容 - 按 10%
[1,100,1000,10000] = [1,100,10000]
筛选以下内容
我想出了以下 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% 时也会起作用?
我认为标准库中没有太多帮助,但我想出了这个"手动"方法:
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必须使用和更新外部状态。