Map: специфичные операции
В Map
типы ключей и значений определяются пользователем. При этом благодаря доступу к значениям по их ключу открываются различные возможности для обработки записей: от получения значения по ключу, до фильтрации ключей и значений по отдельности.
В этом разделе находится описание функций из стандартной библиотеки для обработки ассоциативных списков.
Получение ключей и значений
Для того чтобы получить значение из Map
, вы должны передать его ключ в качестве аргумента функции
get()
. Также поддерживается сокращённый синтаксис - [key]
. Если такой ключ не найден, то вернётся null
.
Помимо этого существует функция getValue()
, которая в случае отсутствия ключа бросит исключение.
Также есть еще две функции для решения проблемы отсутствия ключа:
* getOrElse()
- работает так же, как и для списков: если ключ не найден, то вернётся результат выполнения лямбды.
* getOrDefault()
- если ключ не найден, то вернёт заданное значение по умолчанию.
fun main() {
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap.get("one")) // 1
println(numbersMap["one"]) // 1
println(numbersMap.getOrDefault("four", 10)) // 10
println(numbersMap["five"]) // null
//numbersMap.getValue("six") // exception!
}
Если для выполнения операций вам требуются все ключи или все значения из Map
, то воспользуйтесь свойствами keys
и values
. keys
- это набор (Set
) всех ключей, а values
- коллекция всех значений.
fun main() {
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap.keys) // [one, two, three]
println(numbersMap.values) // [1, 2, 3]
}
Фильтрация
Вы можете фильтровать ассоциативный список с помощью функции
filter()
как и другие коллекции. Для этого передайте filter()
предикат с Pair
в качестве аргумента, что позволит использовать и ключ, и значение в предикате.
fun main() {
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredMap = numbersMap.filter { (key, value) -> key.endsWith("1") && value > 10}
println(filteredMap) // {key11=11}
}
Помимо этого существует две функции фильтрации, специфичные именно для ассоциативного списка:
filterKeys()
для фильтра по ключам и filterValues()
для фильтра по значениям. Обе возвращают новый ассоциативный список, в котором все записи соответствуют заданному предикату. Предикат функции filterKeys()
проверяет только ключи элементов, а предикат функции filterValues()
проверяет только значения.
fun main() {
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
val filteredKeysMap = numbersMap.filterKeys { it.endsWith("1") }
val filteredValuesMap = numbersMap.filterValues { it < 10 }
println(filteredKeysMap) // {key1=1, key11=11}
println(filteredValuesMap) // {key1=1, key2=2, key3=3}
}
Операторы plus
и minus
Из-за наличия доступа к элементам по их ключам операторы
plus
(+
) и
minus
(-
) работают с ассоциативными списками иначе, чем с другими коллекциями.
Оператор plus
возвращает Map
, которая содержит в себе элементы обоих операндов: первым операндом должен быть Map
, а вторым может быть Pair
или другая Map
. Если второй операнд содержит в себе записи с ключами, которые есть в первом операнде, то в результирующую Map
попадут записи из второго операнда.
fun main() {
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap + Pair("four", 4)) // {one=1, two=2, three=3, four=4}
println(numbersMap + Pair("one", 10)) // {one=10, two=2, three=3}
println(numbersMap + mapOf("five" to 5, "one" to 11)) // {one=11, two=2, three=3, five=5}
}
Оператор minus
создаёт Map
на основе первого операнда, исключая те записи, ключи которых есть во втором операнде. Таким образом, второй операнд может быть либо одним ключом, либо коллекцией ключей: списком, множеством и так далее.
fun main() {
val numbersMap = mapOf("one" to 1, "two" to 2, "three" to 3)
println(numbersMap - "one") // {two=2, three=3}
println(numbersMap - listOf("two", "four")) // {one=1, three=3}
}
Подробнее об использовании операторов
plusAssign
(+=
) и
minusAssign
(-=
) с изменяемыми ассоциативными списками см. ниже Операции записи.
Операции записи
Изменяемые ассоциативные списки предлагают специфичные для них операции записи. Такие операции позволяют изменять содержимое ассоциативного списка, используя доступ к значениям по ключу.
Все операции записи придерживаются следующих правил: * Значения можно обновлять. В свою очередь, ключи никогда не меняются: как только вы добавили запись, её ключ остаётся неизменным. * Для каждого ключа всегда есть одно значение, связанное с ним. Вы можете добавлять и удалять записи целиком.
Ниже описаны функции для операций записи из стандартной библиотеки, доступные для использования с изменяемыми ассоциативными списками.
Добавление и обновление записи
Для добавления в изменяемый ассоциативный список новой пары “ключ-значение” используйте функцию
put()
. Когда новая запись помещается в LinkedHashMap
(реализация Map
по умолчанию), она добавляется в неё таким образом, что при итерации Map
она отображается последней. В отсортированных ассоциативных списках положение новых элементов определяется порядком их ключей.
fun main() {
val numbersMap = mutableMapOf("one" to 1, "two" to 2)
numbersMap.put("three", 3)
println(numbersMap) // {one=1, two=2, three=3}
}
Для добавления нескольких записей за раз, используйте функцию
putAll()
. В качестве аргумента она принимает Map
или группу из Pair
: Iterable
, Sequence
, или Array
.
fun main() {
val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
numbersMap.putAll(setOf("four" to 4, "five" to 5))
println(numbersMap) // {one=1, two=2, three=3, four=4, five=5}
}
И put()
, и putAll()
перезаписывают значения, если указанные ключи уже существуют в Map
. Поэтому вы можете использовать их, чтобы обновить значения записей.
fun main() {
val numbersMap = mutableMapOf("one" to 1, "two" to 2)
val previousValue = numbersMap.put("one", 11)
println("value associated with 'one', before: $previousValue, after: ${numbersMap["one"]}") // 11
println(numbersMap) // {one=11, two=2}
}
Помимо этого, вы можете использовать упрощённый вариант для добавления записей в ассоциативный список. Есть два способа:
* Оператор plusAssign
(+=
).
* []
.
fun main() {
val numbersMap = mutableMapOf("one" to 1, "two" to 2)
numbersMap["three"] = 3 // calls numbersMap.put("three", 3)
numbersMap += mapOf("four" to 4, "five" to 5)
println(numbersMap) // {one=1, two=2, three=3, four=4, five=5}
}
Если вызвать эти операторы с ключом, который уже существует в ассоциативном списке, то его значение будет перезаписано.
Удаление записей
Для удаления записи из изменяемой Map
, используйте функцию
remove()
. При вызове remove()
, вы можете передать ей либо только ключ, либо и ключ, и его значение. При этом, если вы передадите и ключ, и значение, то элемент с этим ключом будет удалён только в том случае, если его значение совпадает с переданным значением.
fun main() {
val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
numbersMap.remove("one")
println(numbersMap) // {two=2, three=3}
numbersMap.remove("three", 4) // ничего не удаляет
println(numbersMap) // {two=2, three=3}
}
Также вы можете удалять записи из ассоциативного списка используя свойства keys
или values
: просто вызовите функцию remove()
для них. При вызове remove()
с values
, будет удалена только первая запись с таким значением.
fun main() {
val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3, "threeAgain" to 3)
numbersMap.keys.remove("one")
println(numbersMap) // {two=2, three=3, threeAgain=3}
numbersMap.values.remove(3)
println(numbersMap) // {two=2, threeAgain=3}
}
Оператор minusAssign
(-=
) для изменяемых Map
тоже доступен.
fun main() {
val numbersMap = mutableMapOf("one" to 1, "two" to 2, "three" to 3)
numbersMap -= "two"
println(numbersMap) // {one=1, three=3}
numbersMap -= "five" // ничего не удаляет
println(numbersMap) // {one=1, three=3}
}