Освоюємо 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]
mutableList.remove(4)// можна видалити елемент
println(mutableList) // [5, 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 |
Можна перевірити чи є певний ключ і, якщо нема, то видати певне значення по замовчуванню:
val mymap=mutableMapOf(
"one" to 1,
"two" to 2,
"three" to 3)
val four=mymap.getOrDefault("four", "unknown number")
println (four)
В даному випадку буде виведено на екран unknown number.
Можна також, якщо неіснує певний ключ, то записати новий ключ разом і з новим значенням:
val five =mymap.getOrPut("five"){5}
В даному випадку перевіряється чи є ключ five у колекції, якщо немає то записується разом із значенням 5.
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}
Колекції Kotlin та Java Collection Framework
[ред.]В середині реалізації Kotlin колекцій лежать відповідні реалізації Java. Так по замовчуванню для List використовується реалізація ArrayList, проте можна використати LinkedList при потребі:
import java.util.LinkedList
val list = LinkedList<Int>(listOf(1,2,3,4,6))
В залежності від вибраної реалізації залежить і порядок зберігання значень списку.
Для Set по замовчуванню використовується LinkedHashSet, проте можна використати HashSet та TreeSet.
Для Map по замовчуванню використовується LinkedHashMap, проте можна використати HashMap та TreeMap.
Детальніше про Java колекції можна почитатаи в Освоюємо Java/Колекції