Группировка элементов коллекции
В стандартной библиотеке Kotlin есть функции-расширения для группировки элементов коллекции. Основная функция для группировки -
groupBy()
, которая принимает лямбда-функцию и возвращает Map
. В этой Map
каждый ключ — это результат вычисления лямбда-функции, а соответствующее ему значение — это List
из элементов, значения которых сходятся с полученным результатом от лямбда-функции. Функцию groupBy()
можно использовать, например, для группировки списка строк по их первой букве.
Также groupBy()
может быть передана вторая лямбда-функция — функция преобразования значений. В этом случае ключи, созданные первой лямбдой keySelector
, будут отражать результаты второй лямбды valueTransform
, вместо исходных элементов.
fun main() {
val numbers = listOf("one", "two", "three", "four", "five")
println(numbers.groupBy { it.first().uppercase() }) // {O=[one], T=[two, three], F=[four, five]}
println(numbers.groupBy(
keySelector = { it.first() },
valueTransform = { it.uppercase() }
)) // {o=[ONE], t=[TWO, THREE], f=[FOUR, FIVE]}
}
Если вам требуется сгруппировать элементы, а затем применить какую-либо операцию ко всем группам одновременно, то используйте функцию
groupingBy()
. Она возвращает экземпляр типа
Grouping
. В свою очередь Grouping
позволяет “лениво” применять операции ко всем группам: фактически группы будут создаваться прямо перед выполнением операции.
Grouping
поддерживает следующие операции:
* eachCount()
- подсчитывает количество элементов в каждой группе.
* fold()
и reduce()
- выполняют операции fold и reduce для каждой группы как для отдельной коллекции, после чего возвращают результат.
* aggregate()
- последовательно применяет данную операцию ко всем элементам в каждой группе, после чего возвращает результат. Это общий способ выполнения любых операций с объектом Grouping
. Используйте его для реализации собственных операций, когда операций fold
и reduce
недостаточно.
fun main() {
val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.groupingBy { it.first() }.eachCount()) // {o=1, t=2, f=2, s=1}
}