Создание коллекций

Коллекция с элементами

Самый распространённый способ создать коллекцию - использовать функции listOf<T>(), setOf<T>(), mutableListOf<T>(), mutableSetOf<T>(). Этим функциям в качестве аргументов можно передать элементы, разделяя их запятой. В этом случае тип коллекции указывать не обязательно - компилятор сам его определит. Если же вы хотите создать пустую коллекцию, то её тип необходимо указывать явно.

val numbersSet = setOf("one", "two", "three", "four")
val emptySet = mutableSetOf<String>()

Таким же образом создаются и ассоциативные списки - при помощи функций mapOf() и mutableMapOf(). Ключи и значения ассоциативного списка передаются как объекты Pair (обычно создаются с помощью инфиксной функции to).

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)

Обратите внимание, что нотация to создаёт недолговечный объект Pair, поэтому рекомендуется использовать его только в том случае, если производительность не критична. Чтобы избежать чрезмерного использования памяти, используйте альтернативные способы. Например, вы можете создать MutableMap и заполнить его с помощью операций записи. Функция apply() поможет создать плавную инициализацию.

val numbersMap = mutableMapOf<String, String>()
        .apply {
            this["one"] = "1";
            this["two"] = "2"
        }

Пустая коллекция

Существуют функции для создания пустых коллекций: emptyList(), emptySet() и emptyMap(). При создании пустой коллекции вы должны явно указывать тип элементов, которые будет содержать коллекция.

val empty = emptyList<String>()

Функция-инициализатор для списков

У списков есть конструктор, принимающий размер списка и функцию-инициализатор, которая определяет значение элементов на основе их индексов.

fun main() {
    val doubled = List(3, { it * 2 })  // или MutableList, если вы хотите изменять содержимое
    println(doubled) // [0, 2, 4]
}

Конструкторы конкретных типов

Чтобы создать коллекцию конкретного типа, например, ArrayList или LinkedList, вы можете использовать их конструкторы. Аналогичные конструкторы доступны и для реализаций Set и Map.

val linkedList = LinkedList<String>(listOf("one", "two", "three"))
val presizedSet = HashSet<Int>(32)

Копирование коллекции

Если вам требуется создать новую коллекцию, но с элементами из существующей коллекции, то вы можете её скопировать. Операции копирования из стандартной библиотеки создают неполные копии коллекций - со ссылками на исходные элементы. Поэтому изменение, внесённое в элемент коллекции, будет применено ко всем его копиям.

Функции копирования коллекций, такие как toList(), toMutableList(), toSet() и другие, фиксируют состояние коллекции в определённый момент времени. Результат их выполнения - новая коллекция, но с элементами из исходной коллекции. Если вы добавите или удалите элементы из исходной коллекции, это не повлияет на копии. Копии также могут быть изменены независимо от источника.

fun main() {
    val sourceList = mutableListOf(1, 2, 3)
    val copyList = sourceList.toMutableList()
    val readOnlyCopyList = sourceList.toList()
    sourceList.add(4)
    println("Copy size: ${copyList.size}") // 3

    //readOnlyCopyList.add(4) // ошибка компиляции
    println("Read-only copy size: ${readOnlyCopyList.size}") // 3
}

Эти функции также можно использовать для преобразования типа коллекции, например, для создания множества из списка или наоборот.

fun main() {
    val sourceList = mutableListOf(1, 2, 3)    
    val copySet = sourceList.toMutableSet()
    copySet.add(3)
    copySet.add(4)    
    println(copySet) // [1, 2, 3, 4]
}

В качестве альтернативы вы можете создать новую ссылку на тот же экземпляр коллекции. Новую ссылку можно создать, инициализировав новую переменную для коллекции и записав в нее существующую коллекцию. Однако, изменив новую коллекцию, изменения отразятся во всех ссылках на эту коллекцию.


fun main() {
    val sourceList = mutableListOf(1, 2, 3)
    val referenceList = sourceList
    referenceList.add(4)
    println("Source size: ${sourceList.size}") // 4
}

Подобная инициализация может использоваться для того, чтобы ограничить доступ на изменение коллекции. Например, вы создаёте ссылку List на основе MutableList, если вы попытаетесь изменить коллекцию с помощью этой ссылки, то компилятор выдаст ошибку.

fun main() {
    val sourceList = mutableListOf(1, 2, 3)
    val referenceList: List<Int> = sourceList
    //referenceList.add(4) // ошибка компиляции
    sourceList.add(4)
    println(referenceList) // показывает текущее состояние sourceList - [1, 2, 3, 4]
}

Вызов вспомогательных функций

Коллекции могут создаваться в результате выполнения операций над другими коллекциями. Например, функция filter создаёт новый список элементов, соответствующих заданному фильтру:

fun main() {
    val numbers = listOf("one", "two", "three", "four")  
    val longerThan3 = numbers.filter { it.length > 3 }
    println(longerThan3) // [three, four]
}

Существуют функции, которые преобразуют исходные элементы и возвращают новый список с результатом. Например, функция map:

fun main() {
    val numbers = setOf(1, 2, 3)
    println(numbers.map { it * 3 }) // [3, 6, 9]
    println(numbers.mapIndexed { idx, value -> value * idx }) // [0, 2, 6]
}

Или функция associateWith(), которая создаёт ассоциативный список:

fun main() {
    val numbers = listOf("one", "two", "three", "four")
    println(numbers.associateWith { it.length }) // {one=3, two=3, three=5, four=4}
}

Более подробная информация о таких функциях находится в разделе Операции коллекций.