5.3.8 分组操作符

groupBy(keySelector: (T) -> K): Map<K, List<T>>

将集合中的元素按照条件选择器keySelector(是一个函数)分组,并返回Map。 代码示例:

  1. >>> val words = listOf("a", "abc", "ab", "def", "abcd")
  2. >>> val lengthGroup = words.groupBy { it.length }
  3. >>> lengthGroup
  4. {1=[a], 3=[abc, def], 2=[ab], 4=[abcd]}
  5. ```#### `groupBy(keySelector: (T) -> K, valueTransform: (T) -> V)`
  6. 分组函数还有一个是`groupBy(keySelector: (T) -> K, valueTransform: (T) -> V)`,根据条件选择器keySelector和转换函数valueTransform分组。
  7. 代码示例
  8. ```kotlin
  9. >>> val programmer = listOf("K&R" to "C", "Bjar" to "C++", "Linus" to "C", "James" to "Java")
  10. >>> programmer
  11. [(K&R, C), (Bjar, C++), (Linus, C), (James, Java)]
  12. >>> programmer.groupBy({it.second}, {it.first})
  13. {C=[K&R, Linus], C++=[Bjar], Java=[James]}

这里涉及到一个二元组Pair 类,该类是Kotlin提供的用来处理二元数据组的。 可以理解成Map中的一个键值对,比如Pair(“key”,”value”) 等价于 “key” to “value”。

我们再通过下面的代码示例,来看一下这两个分组的区别:

  1. >>> val words = listOf("a", "abc", "ab", "def", "abcd")
  2. >>> words.groupBy( { it.length })
  3. {1=[a], 3=[abc, def], 2=[ab], 4=[abcd]}
  4. >>> words.groupBy( { it.length },{it.contains("b")})
  5. {1=[false], 3=[true, false], 2=[true], 4=[true]}

我们可以看出,后者是在前者的基础上又映射了一次{it.contains("b")},把第2次映射的结果放到返回的Map中了。#### groupingBy(crossinline keySelector: (T) -> K): Grouping<T, K>

另外,我们还可以使用groupingBy(crossinline keySelector: (T) -> K): Grouping<T, K>函数来创建一个Grouping,然后调用计数函数eachCount统计分组:

代码示例

  1. >>> val words = "one two three four five six seven eight nine ten".split(' ')
  2. >>> words.groupingBy({it.first()}).eachCount()
  3. {o=1, t=3, f=2, s=2, e=1, n=1}

上面的例子是统计words列表的元素单词中首字母出现的频数。

其中,eachCount函数定义如下:

  1. @SinceKotlin("1.1")
  2. @JvmVersion
  3. public fun <T, K> Grouping<T, K>.eachCount(): Map<K, Int> =
  4. // fold(0) { acc, e -> acc + 1 } optimized for boxing
  5. foldTo( destination = mutableMapOf(),
  6. initialValueSelector = { _, _ -> kotlin.jvm.internal.Ref.IntRef() },
  7. operation = { _, acc, _ -> acc.apply { element += 1 } })
  8. .mapValuesInPlace { it.value.element }