Подтвердить что ты не робот

Идиоматический "получить или еще обновить" для immutable.Map?

Каков идиоматический способ getOrElseUpdate для неизменяемых экземпляров .Map?. Я использую фрагмент ниже, но он выглядит многословным и неэффективным.

var map = Map[Key, Value]()

def foo(key: Key) = {
  val value = map.getOrElse(key, new Value)
  map += key -> value
  value
}
4b9b3361

Ответ 1

Позвольте мне подвести итог вашей проблеме:

  • Вы хотите вызвать метод в неизменяемой структуре данных
  • Вы хотите вернуть некоторое значение и переназначить var
  • Поскольку структура данных неизменна, вам необходимо
    • возвращает новую неизменяемую структуру данных или
    • выполнить назначение внутри метода, используя поставляемое закрытие

Итак, ваша подпись должна выглядеть как

def getOrElseUpdate(key: K): Tuple2[V, Map[K,V]]
//... use it like
val (v, m2) = getOrElseUpdate(k)
map = m2

или

def getOrElseUpdate(key: K, setter: (Map[K,V]) => Unit): V
//... use it like
val v = getOrElseUpdate(k, map = _)

Если вы можете жить с одним из этих решений, вы можете добавить свою версию с неявным преобразованием, но, судя по только подписям, я бы не думал, что любой из них находится в стандартной библиотеке.

Ответ 2

Я бы, вероятно, использовал метод getOrElseUpdated, подобный этому:

def getOrElseUpdated[K, V](m: Map[K, V], key: K, op: => V): (Map[K, V], V) =
  m.get(key) match {
    case Some(value) => (m, value)
    case None => val newval = op; (m.updated(key, newval), newval)
  }

который возвращает исходную карту, если m имеет отображение для key или другое отображение с добавлением отображения key -> op. Определение этого метода похоже на getOrElseUpdate of mutable.Map.

Ответ 3

Нет такого пути - мутация карты (обновление), когда вы получаете значение карты, является побочным эффектом (что противоречит неизменности/функциональному стилю программирования).

Если вы хотите создать новую неизменяемую карту со значением по умолчанию, если другое значение для указанного ключа не существует, вы можете сделать следующее:

map + (key -> map.getOrElse(key, new Value)) 

Ответ 4

Почему бы не использовать withDefault или withDefaultValue, если у вас есть неизменяемая карта?