Операции преобразования коллекций
Стандартная библиотека Kotlin предоставляет набор функций-расширений для преобразования коллекций. Эти функции создают новые коллекции на основе существующих, применяя заданные правила преобразования. На этой странице мы рассмотрим доступные функции преобразования коллекций.
Отображение
Преобразование с отображением создает коллекцию из результатов применения функции к элементам другой коллекции. Основная функция отображения — map(). Она применяет заданную лямбда-функцию к каждому элементу по очереди и возвращает список результатов этой лямбда-функции. Порядок результатов совпадает с исходным порядком элементов. Чтобы применить преобразование, которое дополнительно использует индекс элемента в качестве аргумента, используйте mapIndexed().
fun main() {
//sampleStart
val numbers = setOf(1, 2, 3)
println(numbers.map { it * 3 })
println(numbers.mapIndexed { idx, value -> value * idx })
//sampleEnd
}
Если при преобразовании для некоторых элементов получается null, отфильтровать null из результирующей коллекции можно, вызвав функцию mapNotNull() вместо map() или mapIndexedNotNull() вместо mapIndexed().
fun main() {
//sampleStart
val numbers = setOf(1, 2, 3)
println(numbers.mapNotNull { if ( it == 2) null else it * 3 })
println(numbers.mapIndexedNotNull { idx, value -> if (idx == 0) null else value * idx })
//sampleEnd
}
При преобразовании отображений есть два варианта: преобразовать ключи, оставив значения без изменений, или наоборот. Чтобы применить заданное преобразование к ключам, используйте mapKeys(); функция mapValues(), в свою очередь, преобразует значения. Обе функции используют преобразования, принимающие в качестве аргумента запись отображения, поэтому с их помощью можно работать и с ключом, и со значением.
fun main() {
//sampleStart
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
println(numbersMap.mapKeys { it.key.uppercase() })
println(numbersMap.mapValues { it.value + it.key.length })
//sampleEnd
}
Объединение
Объединение в пары — это преобразование, при котором из элементов, занимающих одинаковые позиции в двух коллекциях, создаются пары. В стандартной библиотеке Kotlin для этого используется функция-расширение zip().
При вызове для коллекции или массива с другой коллекцией (или массивом) в качестве аргумента функция zip() возвращает List объектов Pair. Элементы исходной коллекции становятся первыми элементами этих пар.
Если размеры коллекций различаются, размер результата zip() будет равен размеру меньшей коллекции; последние элементы большей коллекции не войдут в результат.
Функцию zip() также можно вызвать в инфиксной форме a zip b.
fun main() {
//sampleStart
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors zip animals)
val twoAnimals = listOf("fox", "bear")
println(colors.zip(twoAnimals))
//sampleEnd
}
Также можно вызвать zip() с функцией преобразования, принимающей два параметра: элемент исходной коллекции и элемент аргумента. В этом случае результат List содержит значения, возвращенные функцией преобразования для пар элементов исходной коллекции и аргумента, занимающих одинаковые позиции.
fun main() {
//sampleStart
val colors = listOf("red", "brown", "grey")
val animals = listOf("fox", "bear", "wolf")
println(colors.zip(animals) { color, animal -> "The ${animal.replaceFirstChar { it.uppercase() }} is $color"})
//sampleEnd
}
Если у вас есть List из Pair, можно выполнить обратное преобразование — разделение пар, которое создает из этих пар два списка:
Первый список содержит первые элементы каждой
Pairиз исходного списка.Второй список содержит вторые элементы.
Чтобы разделить список пар, вызовите unzip().
fun main() {
//sampleStart
val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)
println(numberPairs.unzip())
//sampleEnd
}
Ассоциирование
Преобразования ассоциирования позволяют создавать отображения из элементов коллекции и связанных с ними значений. В зависимости от типа ассоциирования элементы могут становиться ключами или значениями в отображении.
Основная функция ассоциирования associateWith() создает Map, в котором элементы исходной коллекции являются ключами, а значения формируются из них с помощью заданной функции преобразования. Если два элемента равны, в отображении остается только последний из них.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateWith { it.length })
//sampleEnd
}
Для создания отображений, в которых элементами коллекции являются значения, предназначена функция associateBy(). Она принимает функцию, которая возвращает ключ на основе значения элемента. Если ключи двух элементов равны, в отображении остается только последний из них.
Функцию associateBy() также можно вызвать с функцией преобразования значений.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
println(numbers.associateBy { it.first().uppercaseChar() })
println(numbers.associateBy(keySelector = { it.first().uppercaseChar() }, valueTransform = { it.length }))
//sampleEnd
}
Еще один способ создавать отображения, в которых и ключи, и значения формируются из элементов коллекции, — использовать функцию associate(). Она принимает лямбда-функцию, возвращающую Pair: ключ и значение соответствующей записи отображения.
Обратите внимание: associate() создает недолговечные объекты Pair, что может повлиять на производительность. Поэтому associate() следует использовать, когда производительность не критична или этот вариант предпочтительнее других.
Пример такого случая — когда ключ и соответствующее ему значение создаются одновременно из одного элемента.
fun main() {
data class FullName (val firstName: String, val lastName: String)
fun parseFullName(fullName: String): FullName {
val nameParts = fullName.split(" ")
if (nameParts.size == 2) {
return FullName(nameParts[0], nameParts[1])
} else throw Exception("Wrong name format")
}
//sampleStart
val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")
println(names.associate { name -> parseFullName(name).let { it.lastName to it.firstName } })
//sampleEnd
}
Здесь мы сначала вызываем функцию преобразования для элемента, а затем создаем пару из свойств результата этой функции.
Сведение
Если вы работаете с вложенными коллекциями, вам могут пригодиться функции стандартной библиотеки, обеспечивающие прямой доступ к элементам вложенных коллекций.
Первая такая функция — flatten(). Ее можно вызвать для коллекции коллекций, например для List из Set. Функция возвращает единый List, содержащий все элементы вложенных коллекций.
fun main() {
//sampleStart
val numberSets = listOf(setOf(1, 2, 3), setOf(4, 5, 6), setOf(1, 2))
println(numberSets.flatten())
//sampleEnd
}
Другая функция — flatMap() — позволяет гибко обрабатывать вложенные коллекции. Она принимает функцию, преобразующую элемент коллекции в другую коллекцию. В результате flatMap() возвращает единый список значений, полученных при применении этой функции ко всем элементам. Таким образом, flatMap() работает как последовательный вызов map() (с коллекцией в качестве результата отображения) и flatten().
data class StringContainer(val values: List<String>)
fun main() {
//sampleStart
val containers = listOf(
StringContainer(listOf("one", "two", "three")),
StringContainer(listOf("four", "five", "six")),
StringContainer(listOf("seven", "eight"))
)
println(containers.flatMap { it.values })
//sampleEnd
}
Строковое представление
Если нужно получить содержимое коллекции в удобочитаемом формате, используйте функции преобразования коллекций в строки: joinToString() и joinTo().
joinToString() создает одну String из элементов коллекции на основе переданных аргументов. joinTo() делает то же самое, но добавляет результат в заданный объект Appendable.
При вызове с параметрами по умолчанию эти функции возвращают результат, аналогичный вызову toString() для коллекции: String строковых представлений элементов, разделенных запятыми и пробелами.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
println(numbers)
println(numbers.joinToString())
val listString = StringBuffer("The list of numbers: ")
numbers.joinTo(listString)
println(listString)
//sampleEnd
}
Чтобы создать строковое представление в заданном формате, можно указать значения аргументов функции separator, prefix и postfix. Полученная строка будет начинаться с prefix и заканчиваться на postfix. После каждого элемента, кроме последнего, будет добавлено separator.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
println(numbers.joinToString(separator = " | ", prefix = "start: ", postfix = ": end"))
//sampleEnd
}
Для больших коллекций можно задать limit — количество элементов, включаемых в результат. Если размер коллекции превышает limit, все остальные элементы будут заменены одним значением аргумента truncated.
fun main() {
//sampleStart
val numbers = (1..100).toList()
println(numbers.joinToString(limit = 10, truncated = "<...>"))
//sampleEnd
}
Наконец, чтобы настроить представление самих элементов, задайте функцию transform.
fun main() {
//sampleStart
val numbers = listOf("one", "two", "three", "four")
println(numbers.joinToString { "Element: ${it.uppercase()}"})
//sampleEnd
}
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/collection-transformations.html