Освоюємо 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")}")
Результат:
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}")
Результат:
Кількість елементів: 4 1 є у множині Множини рівні: true |
MutableSet підтриує операції з класу MutableCollection.
Реалізація MutableSet за замовчуванням зберігає порядок елементів. Тож функції, що покладаються на порядок елементів як то first() чи last(), повертають передбачуваний результат (перше або останнє значення).
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") // те ж саме
Результат:
{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())
}
Результат:
Перша машина: 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}")
}
}
Результат:
Перший спосіб: 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)
}
Результат:
[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)
}
Результат:
[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}