Освой Kotlin играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Map

Ассоциативные списки с уникальными ключами и любыми значениями (дубликаты ключей не допускаются, значения могут быть одинаковыми). Связь между ключами и значениями происходит через специальную форму вызова метода (инфиксный вызов) to.

mapOf()

Неизменяемый Map создаётся через mapOf(). Вы не можете добавлять или удалять пару ключа и значения или обновлять значение в ключе:


val map = mapOf(1 to "one", 3 to "three", 9 to "nine")
println(map.javaClass) // class java.util.LinkedHashMap

Другой способ создания через Pair.


val map = mapOf(Pair(1, "one"), Pair(3, "three"), 9 to "nine") // оставлен один вариант через to

Вывести содержимое коллекции можно через вызов самой переменной.


println(map)

{1=one, 3=three, 9=nine}

В примере ключи были числами, а значения строками. Можно сделать наоборот, ключи будут строками, а значения числами.


val map = mapOf("One" to 1, "Two" to 2, "Eight" to 8)
// равносильно val map: Map<String, Int> = mapOf("One" to 1, "Two" to 2, "Eight" to 8)
println(map)

Проверить существование ключа или значения можно через containsKey() и containsValue().


map.containsKey("One")

Получить значение у заданного ключа можно через get() или getValue(). Если указать несуществующий ключ, то get() вернёт null, а getValue() выбросит исключение NoSuchElementException. Также можно получить значение ключа через квадратные скобки.


val map = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3)

println(map.getValue("One"))
println(map["Two"])

Во избежание проблем с исключениями применяйте getOrElse() или getOrDefault().


// анонимная функция для несуществующего ключа
val map = mapOf("One" to 1, "Two" to 2, "Eight" to 8)
val number = map.getOrElse("One1") {"No such number"}
println(number)

// Значение по умолчанию
val map = mapOf("One" to 1, "Two" to 2, "Eight" to 8)
val number = map.getOrDefault("Cat", 0)
println(number)

Перебрать все ключи и их значения можно в цикле for.


val map = mapOf("One" to 1, "Two" to 2, "Three" to 3)
for((key, value) in map){
    println("Key is $key, value is $value")
}

А можно через функцию forEach().


val map = mapOf("One" to 1, "Two" to 2, "Three" to 3)
map.forEach{entry ->
    println("Значение ${entry.value} у ключа ${entry.key}")
}

Значение 1 у ключа One Значение 2 у ключа Two Значение 3 у ключа Three

Применим функцию отбора и преобразования.


val map = mapOf(1 to "one", 3 to "three", 9 to "nine")
println(map.mapValues { it.value.toUpperCase() })

{1=ONE, 3=THREE, 9=NINE}

mutableMapOf()

Изменяемый Map.


val currenciesMutableMap: MutableMap<String, String> =
        mutableMapOf("Гривна" to "Украина", "Доллар" to "США", "Рубль" to "Россия")
println("Страны: ${currenciesMutableMap.values}") // Страны: [Украина, США, Россия]
println("Валюты: ${currenciesMutableMap.keys}") // Валюты: [Гривна, Доллар, Рубль]
currenciesMutableMap.put("Тугрик", "Монголия")
currenciesMutableMap.remove("Доллар")
println(currenciesMutableMap) //{Гривна=Украина, Рубль=Россия, Тугрик=Монголия}

Так как мы имеем дело с изменяемым Map, то у него есть дополнительные возможности. Например, мы можем добавить новую запись через put().


val map = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3)
map.put("Four", 4)
println(map)

Можно добавить через оператор +=. Если ключ уже существует, то его значение будет переписано.


val map = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3)
map.put("Four", 4)
map += "Five" to 5
map += "Two" to 22
println(map) //{One=1, Two=22, Three=3, Four=4, Five=5}

Можно сначала подготовить несколько записей для вставки и вставить их сразу через putAll():


val map = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3)
val entry1 = Pair("Four", 4)
val entry2 = Pair("Five", 5)
val entryToAdd = mapOf(entry1, entry2)
map.putAll(entryToAdd)
println(map)

Объединить две коллекции можно также через putAll().


val mapA = mutableMapOf<String, Int>("a" to 1, "b" to 2)
val mapB = mutableMapOf<String, Int>("a" to 2, "d" to 4)
mapA.putAll(mapB)
println(mapA) // {a=2, b=2, d=4}

При совпадении ключей побеждает более поздний вызов, поэтому ключ из mapB перепишет ключ из mapA.

Удалить запись можно по ключу через remove():


map.remove("Two")

Перегруженная версия remove() удалит запись только при совпадении ключа и его значения.


val map = mutableMapOf("One" to 1, "Two" to 2, "Three" to 3)
val entry1 = Pair("Four", 4)
val entry2 = Pair("Five", 5)
val entryToAdd = mapOf(entry1, entry2)
map.putAll(entryToAdd)
map.remove("Two", 3) // не удалит
map.remove("Five", 5) // удалит
println(map)

Очистить все записи можно через clear(). Но сам объект остаётся.

Можно перевести в список List через toList().


val list = map.toList()
println(list)

//[(One, 1), (Two, 2), (Three, 3), (Four, 4), (Five, 5)]

hashMapOf()

Изменяемый HashMap.


//val personsHashMap: java.util.HashMap<Int, String> = 
//        hashMapOf(1 to "Барсик", 2 to "Мурзик", 3 to "Рыжик")
val personsHashMap = hashMapOf(1 to "Барсик", 2 to "Мурзик", 3 to "Рыжик")		
personsHashMap.put(4, "Васька")
personsHashMap.remove(2)
println(personsHashMap[1])

Получить значение по ключу можно через метод getOrDefault() (относится к Java 8). Если ключ не будет найден, то подставится значение по умолчанию.


fun byName(name: String): String =
        map.getOrDefault(name, "cat")

private val map: Map<String, String> = hashMapOf(
        "one" to "value one",
        "two" to "value two",
        "three" to "value three"
)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    println(byName("one"))
    // укажем несуществующий ключ
    println(byName("barsik"))
}

Если вынуждены использовать Java 7, то используйте квадратные скобки и элвис-оператор.


fun byName(name: String): String = map[name] ?: "cat"

linkedHashMap()

Изменяемый LinkedHashMap.


val postalHashMap: java.util.LinkedHashMap<String, String> =
        linkedMapOf("NG" to "Nigeria","AU" to "Australia","CA" to "Canada")
postalHashMap.put("NA", "Namibia")
postalHashMap.remove("AU")
postalHashMap.get("CA") // Canada

sortedMapOf()

Изменяемый SortedMap, сортировка по ключу.


val personsSortedMap: java.util.SortedMap<Int, String> = 
        sortedMapOf(2 to "Барсик", 1 to "Рыжик", 3 to "Мурзик")
personsSortedMap.put(7, "Васька")
personsSortedMap.remove(3)
Реклама