Kotlin中groupBy和groupingBy使⽤中的对⽐
今天在看Kotlin的Coroutines官⽅⽂档练英⽂的时候,它有个,在⾥⾯要实现⼀个aggregate的功能,先来看看我的初版实现:
fun List<User>.aggregate(): List<User>{
val map =upBy{ it.login }
val result = ArrayList<User>(map.keys.size)
for(login in map.keys){
result.add(User(login, map[login]?.sumOf{ it.contributions }?:0))
}
result.sortByDescending{ it.contributions }
groupby分组return result
}
再来看看官⽅的实现:
fun List<User>.aggregate(): List<User>= groupBy { it.login }
.map{(k,v)->User(k, v.sumOf{ it.contributions })}
.sortedByDescending{ it.contributions }
我⾃⼰的实现和官⽅的解决⽅案都⽤了groupBy,这个函数的功能就是根据给定的key遍历list进⾏分组:
/**
* Groups elements of the original collection by the key returned by the given [keySelector] function
* applied to each element and returns a map where each group key is associated with a list of corresponding elements.
*
* The returned map preserves the entry iteration order of the keys produced from the original collecti
on.
*
* @llections.upBy
*/
public inline fun<T, K> Iterable<T>.groupBy(keySelector:(T)-> K): Map<K, List<T>>{
return groupByTo(LinkedHashMap<K, MutableList<T>>(), keySelector)
}
相⽐官⽅我没有⽤map⽽是⽤了⼀个局部变量来接收groupBy的结果供后续处理,排序也没有注意到有⼀个sortByDescending还有⼀
个sortedByDescending,明显不如官⽅的简练.
但是在⽂章中后⾯⼜说:An alternative is to use the function groupingBy instead of groupBy. 还有⼀个groupingBy`吗?之前都没有注意到有这个东西,让我来康康:
/**
* Creates a [Grouping] source from a collection to be used later with one of group-and-fold operations
* using the specified [keySelector] function to extract a key from each element.
*
* @upingByEachCount
*/
@SinceKotlin("1.1")
public inline fun<T, K> Iterable<T>.groupingBy(crossinline keySelector:(T)-> K): Grouping<T, K>{
return object: Grouping<T, K>{
override fun sourceIterator(): Iterator<T>=this@groupingBy.iterator()
override fun keyOf(element: T): K =keySelector(element)
}
}
看代码这⾥并没有进⾏遍历操作⽽是直接返回了⼀个Grouping类型的源数据的界⾯.不处理数据直接交给后续的操作处理.在这个例⼦中相对于groupBy可以减少⼀次遍历.那⽤groupingBy如何实现呢?
fun List<User>.aggregateFromGrouping(): List<User>= groupingBy { it.login }
.aggregate<User, String, Int>{ _, accumulator, element, _ ->
}
.map{(k, v)->User(k, v)}
.sortedByDescending{ it.contributions }
看起来⽐groupBy复杂⼀点点,在aggregate这真正的遍历操作数据的这⼀步这⾥需要要繁杂⼀点点,但是因为少了⼀次遍历,在我的电脑上重复⼀千万次会⽐使⽤groupBy快⼀些:
println("start groupingBy")
val s2 = System.currentTimeMillis()
repeat(10000000){
actual= list.aggregateFromGrouping()
}
println("end groupingBy ${System.currentTimeMillis()-s2}ms")
println("start groupBy")
val s1 = System.currentTimeMillis()
repeat(10000000){
actual= list.aggregate()
}
println("end groupBy ${System.currentTimeMillis()-s1}ms")
-------------------------------result-------------------------
start groupingBy
end groupingBy 2064ms
start groupBy
end groupBy 2439ms
综上在性能要求严格的情况下推荐使⽤groupingBy.
⽔完,下班.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论