Перейти до вмісту

Освоюємо Kotlin/Колекції

Матеріал з Вікіпідручника


Колекції - це набір класів для роботи з даними. Колекції в Kotlin представлені типами List, Set, Map, MutableMap, MutableList, MutableMap та ArrayDeque. Приставка Mutable означає, що колекцію можна змінювати. Прості List, Set та Map - не змінюються. Вміст ArrayDeque також можна змінювати. Робота з колекціями схожа на роботу з масивами.

List

[ред.]

List - це список елементів одного типу, які можуть повторюватись.

val numbers = listOf("one", "two", "three", "four") //список String
val numbers2 = listOf<String>("one", "two", "three", "four") // можна явно вказати тип елементів списку
println("Number of elements: ${numbers.size}")
println("Third element: ${numbers.get(2)}") // можна так звертатись до елементу списку
println("Fourth element: ${numbers[3]}") //а можна як до масив
println("Index of element \"two\" ${numbers.indexOf("two")}")
Standard input or output Результат:
Number of elements: 4
Third element: three
Fourth element: four
Index of element "two" 1

В mutable колекціях ми можемо видаляти елементи, замінювати їх та додавати нові:

    val numbers2 = mutableListOf<String>("one", "two", "three", "four")
    numbers2.removeAt(1) // видаляємо перший(насправді другий) елемент списку
    numbers2[0] ="first" //заміняєм нульовий елемент
    numbers2.set(2, "third") // заміняєм другий елемент списку
    numbers2.add("fives") // додаємо новий елемент
    println(numbers2) // [first, three, third, five]

Якщо необхідно на базі List створити новий MutableList, то можна скористатись відповідною функціїю toMutableList():

    val list: List<Int> = listOf(5, 4, 3, 56)
    val mutableList=list.toMutableList()
    mutableList.add(90)
    println(mutableList) // [5, 4, 3, 56, 90]

Set

[ред.]

Set - це множина елементів, які не повторюються. Порядок елементів не визначений. null також може бути елементом множини, але лише один раз. Дві колекції Set рівні, якщо вони однакових розмірів і у них ідентичні елементи.

    val numbers = setOf(1, 2, 3, 4)
    println("Кількість елементів: ${numbers.size}")
    if (numbers.contains(1)) println("1 є у множині")

    val numbersBackwards = setOf(4, 3, 2, 1)
    println("Множини рівні: ${numbers == numbersBackwards}")
Standard input or output Результат:
Кількість елементів: 4
1 є у множині
Множини рівні: true

MutableSet підтриує операції з класу MutableCollection.

Реалізація MutableSet за замовчуванням зберігає порядок елементів. Тож функції, що покладаються на порядок елементів як то first() чи last(), повертають передбачуваний результат (перше або останнє значення).

Note При використанні, в якості елементів Set, класів даних (data class), вміст об'єктів буде порівнюватись автоматично і, якщо будуть об'єкти з однаковими властивостями, то включатись в Set буде лише один з цих об'єктів.

Map

[ред.]

Map та MutableMap хоч не є нащадками інтерфейсу Collection, відноситься також до колекцій. Map зберігає значення у вигляді пари ключ-значення. Два об'єкта Map рівні, якщо в них однакові пари, незалежно від їхнього місця в середині Map.

    val numbersMap = mutableMapOf("one" to 1, "two" to 2)
    numbersMap.put("three", 3) // можна так
    numbersMap["one"] = 11 // а можна так з квадратними дужками
    println(numbersMap) // {one=11, two=2, three=3}

    println("Всі ключі: ${numbersMap.keys}")
    println("Всі значення: ${numbersMap.values}")
    if ("one" in numbersMap) println("значення ключа \"one\": ${numbersMap["one"]}")
    if (11 in numbersMap.values) println("Значення 11 є у map")
    if (numbersMap.containsValue(11)) println("Значення 11 є у map") // те ж саме
Standard input or output Результат:
{one=11, two=2, three=3}
Всі ключі: [one, two, three]
Всі значення: [11, 2, 3]
значення ключа "one": 11
Значення 11 є у map
Значення 11 є у map

В колекціях і, зокрема, в Map не обов'язково можуть бути базові типи. Колекція може містити і інші об'єкти створені програмістом. Наприклад, створимо клас машина (Car), який міститиме марку машини, її колір та ціну. Map міститиме певний порядковий номер машини зіставлений з об'єктом Car.

class Car (val name:String, val color:String, val price:Double){
    /**
     * повертаємо інформацію про назву, колір і ціну машини
     */
    fun getInformation():String = "$name $color $price"
}

fun main(){
    var car1= Car("Honda", "blue", 11000.0)
    var car2= Car("BMW", "red", 12345.0)
    var car3= Car("Mersedes", "white", 11550.0)
    val carMap = mapOf(1 to car1, 2 to car2, 3 to car3)
    println("Перша машина: "+carMap[1]?.getInformation())
}
Standard input or output Результат:
Перша машина: Honda blue 11000.0

Якщо потрібно пройтись почергово по елементах Map, то можна використати цикл або forEach:

fun main(){
    var propertiesMap=mutableMapOf<String, Boolean>()
    propertiesMap["Big"]=true
    propertiesMap["Printable"]=false
    propertiesMap["Readable"]=true
    
    println("Перший спосіб:")
    for (prop in propertiesMap.entries.iterator()){
        println("Key: ${prop.key}, Value: ${prop.value}")
    }
    println("Другий спосіб:")
    propertiesMap.forEach{prop->
        println("Key: ${prop.key}, Value: ${prop.value}")
    }
}
Standard input or output Результат:
Перший спосіб:
Key: Big, Value: true
Key: Printable, Value: false
Key: Readable, Value: true
Другий спосіб:
Key: Big, Value: true
Key: Printable, Value: false
Key: Readable, Value: true

ArrayDeque

[ред.]

ArrayDeque - це реалізація двохсторонньої черги. Тобто в дану колекцію дані можна додавати як на перед черги так і в кінець.

val deque = ArrayDeque(listOf(1, 2, 3, 4, 5))

deque.addFirst(0)
deque.addLast(6)
println(deque) // [0, 1, 2, 3, 4, 5, 6]

println(deque.first()) // 0
println(deque.last()) // 6

deque.removeFirst()
deque.removeLast()
println(deque) // [1, 2, 3, 4, 5]

Функції для роботи з колекціями

[ред.]

Стандартна бібліотека Kotlin надає ряд функцій, спеціально створених для роботи з колекціями. Розглянемо деякі з них.

Функція map

[ред.]

Функція map() дозволяє трансформувати оригінальну колекцію у нову. При цьому ця лямбда функція проходить по елементах колекції і для кожного елемента повертає результат цієї лямбда функції. В результаті створюється новий список з отриманих значень:

Як приклад розглянемо збільшення кожного елементу списку на 5 та на 10.

fun main(){
    val numberList=listOf(1,2,3,4,5)
    //перший спосіб (збільшуєм у 5 раз)
    val numberList1=numberList.map{it*5}
    println(numberList1) // [5, 10, 15, 20, 25]
    //другий спосіб (збільшуєм у 10 раз)
    val numberList2=numberList.map{number->//замість it використовуємо назву
        val myNum=number*10
        myNum // останній рядок є присвоюваним значенням
    }
    println(numberList2) // [10, 20, 30, 40, 50]
}

Функцію можна застосовувати до всіх видів колекцій, включаючи Map. Детальніше тут.

Сортування колекцій

[ред.]

Для сортування колекцій як то списки існують функції, що починаються зі слова sort:

val numberList=listOf(1,4,3,4,2)
val sortedList=numberList.sorted() //1 2 3 4 4
val sortedList2=numberList.sortedDescending() //4 4 3 2 1

Об'єкти можна посортувати за значенням поля:

data class Car(val name:String, val price:Int)
fun main(){
      val carList=listOf(
          Car("Toyota", 500),
          Car("BMW", 565),
          Car("Nissan", 456),
          Car("Honda", 800)
      )
    val sortedCarList=carList.sortedBy { it.price } //вказуємо поле для сортування
    println(sortedCarList)
}
Standard input or output Результат:
[Car(name=Nissan, price=456), Car(name=Toyota, price=500), Car(name=BMW, price=565), Car(name=Honda, price=800)]

Фільтрування колекцій

[ред.]

Ми можемо відфільтруваати вміст колекції за певною умовою використовуючи функцію filter():

data class Car(val name:String, val price:Int)
fun main(){
      val carList=listOf(
          Car("Toyota", 500),
          Car("BMW", 565),
          Car("Nissan", 456),
          Car("Honda", 800)
      )
    val newCarList=carList.filter{it.price>500}
    println(newCarList)
}
Standard input or output Результат:
[Car(name=BMW, price=565), Car(name=Honda, price=800)]

Детальніше читайте тут

Пошук в колекціях

[ред.]

Можна здійснити пошук в колекціях за допомогою функції find():

val newCarList=carList.find{it.price==500}

В результаті видасть перший елемент, що співпав з умовою. Якщо необхідно здійснити пошуку з кінця, то використовуємо функцію findLast()

forEach

[ред.]

Можна пройтися по всіх елементах колекції з використанням функції forEach:

carList.forEach{println(it)}

Поєднання функцій

[ред.]

Роботу із вмістом колекцій можна проводити поєднуючи функції ланцюжком, використовуючи оператор .(точку):

val newList=carList.filter { it.price>500 }.sortedBy{it.price}