Идиоматический способ обновления нескольких значений в scala.immutable.Map

Мне нужно обновить (получить и увеличить) два разных значения, привязанных к двум ключам на карте. Два ключа могут иногда совпадать. У меня есть следующий код на данный момент:

// val map: Map[Int, Int]
// val key1, key2: Int
if (key1 == key2) {
  tailRecFunction(someArg, map 
    + Tuple2(key1, 2 + map.getOrElse(key1, 0)))
} else {
  tailRecFunction(someArg, map 
    + Tuple2(key1, 1 + map.getOrElse(key1, 0))
    + Tuple2(key2, 1 + map.getOrElse(key2, 0)))
}

Как вы можете видеть, если вы используете else блок, когда key1 == key2то значение при key1 == key2 будет неправильно увеличен на 1 вместо 2 --- второй кортеж ошибочно обновляет исходное значение, а не значение, примененное первым кортежем.
Есть ли более чистый способ написать это?

2 ответа

Решение

Прежде всего, вы можете упростить карту, чтобы вернуться 0 когда нет ключа:

val map0 = Map.empty[Int, Int] withDefaultValue 0

Тогда вы можете смело звонить map(key) вместо map.getOrElse(key, 0),

Во-вторых, вы можете использовать синтаксис стрелки для создания Tuple2 экземпляров. Т.е. key -> value вместо Tuple2(key, value),

В-третьих, я бы не стал вводить if ... then ... else совсем. Просто обновите карту для каждого ключа последовательно:

def addKey(map: Map[Int, Int], key: Int) = map + (key -> (map(key) + 1))

val map1 = addKey(map0, key1)
val map2 = addKey(map1, key2)
tailRecFunction(someArg, map2)

Другой SO-ответ предлагает использовать моноидные характеристики Map (ScalaZ):

tailRecFunction(someArg, map |+| Map(key1 -> 1) |+| Map(key2 -> 1))

|+| Оператор суммирует значения, принадлежащие одному ключу.

Другие вопросы по тегам