如何有效地从Kotlin的集合(前N个)中获取N个最低值?
除了collectionOrSequence.sortedby{it.value}.take(n)
之外还有其他方法吗?
假设我有一个包含+100500元素的集合,我需要找到10个最低的元素。恐怕sortedby
会创建新的临时集合,以后只需要10个项目。
答案 0 :(得分:3)
您可以保留n个最小元素的列表,然后根据需要进行更新,例如
fun <T : Comparable<T>> top(n: Int, collection: Iterable<T>): List<T> {
return collection.fold(ArrayList<T>()) { topList, candidate ->
if (topList.size < n || candidate < topList.last()) {
// ideally insert at the right place
topList.add(candidate)
topList.sort()
// trim to size
if (topList.size > n)
topList.removeAt(n)
}
topList
}
}
这样,您只需将列表中的当前元素与前n个元素中的最大元素进行一次比较,通常比对整个列表进行排序https://pl.kotl.in/SyQPtDTcQ
答案 1 :(得分:2)
如果您在JVM上运行,则可以使用Guava的Comparators.least(int, Comparator)
,它比上述任何建议使用的算法都更高效,占用O(n + k log k)时间和O(k)内存在大小为n的集合中查找最低的k个元素,这与zapl的算法(O(nk log k))或Lior的算法(O(nk))相反。
答案 2 :(得分:1)
您还有更多的烦恼。
collectionOrSequence.sortedby{it.value}
运行java.util.Arrays.sort
,它将运行timSort(如果需要,则运行mergeSort)。{it.value}
)->额外的有意义的开销。java.util.Arrays.sort
会将集合转换为Array并返回到列表-另外2次转换(您要避免,但这是次要的)有效的方法可能是:
map
用于比较的值列表:O(n)个转换(每个元素一次),而不是O(n * log.n)或更多。mutableList
很合适。这将使您从O(n * log.n)转到O(n)。
当然,如果时间紧迫-始终最好对特定情况进行基准测试。
如果您第一步就设法提取基元以进行比较(例如int
或long
),那将更加有效。
答案 3 :(得分:1)
如果集合具有随机分布的1k +值,我建议您根据典型的quickSort算法(以降序排列,并采用前N个元素)实现自己的排序方法。