Collections

Мапы

Language

Map это Iterable состоящее из пар ключ значение (также называемых связкой или ассоциативным массивом). Scala Объект Predef предоставляет неявное преобразование, позволяющее записать пару (ключ, значение) используя альтернативный синтаксис вида ключ -> значение . Например, Map("x" -> 24, "y" -> 25, "z" -> 26) означает тоже самое что и Map(("x", 24), ("y", 25), ("z", 26)), но читается лучше.

Основные операции на мапах аналогичны темже операциям на множества. Рассмотрим в следующей таблице обобщеный и сгруппированный по категориям список методов на мапах:

  • Запросы операции apply, get, getOrElse, contains, и isDefinedAt. Они превращают мапы в частично определенные функции от ключей к значениям. Основной “запросный метод” на мапах это : def get(key): Option[Value]. Операция “m get key” проверяет содержит ли мапа связанное значение для ключа key. Если да, то возвращает это связанное значение обернутое в Some. Если же нет, то get возвращает None. На мапах еще определен метод apply, которое напрямую возвращает связанное с заданным ключем значение, без оборачивания его в Option. В этом случае, когда ключ не определен, будет брошено исключение.
  • Добавление и обновления +, ++, updated, которые позволяют добавлять новые пары к мапам или изменять существующие.
  • Удаления -, --, которые позволяют удалять пары из мап.
  • Создание подколлеций keys, keySet, keysIterator, values, valuesIterator, которые возвращают ключи и значения мап отдельно в различных формах.
  • Трансформации filterKeys и mapValues, которые создают новую мапу через фильтрацию и преобразования элементов существующей мапы.

Операции на Классе Map

ПРИМЕР ЧТО ДЕЛАЕТ
Запросы:  
ms get k Возвращает значение связанное с ключом k в мапе ms обернутое в опшен, None если значение не найдено.
ms(k) (либо эквивалент ms apply k) Возвращает напрямую значение, связанное с ключом k на мапе ms, или исключение, если оно не найдено.
ms getOrElse (k, d) Значение, связанное с ключом k на мапе ms, или значением по умолчанию d, если не найдено.
ms contains k Проверяет, содержит ли ms значение для ключа k.
ms isDefinedAt k Тоже самое что и contains.
Подколлекции:  
ms.keys Итерируемая коллекция, содержащая каждый ключ из мапы ms.
ms.keySet Множество, содержащее каждый ключ из ms.
ms.keysIterator Итератор, выдающий каждый ключ из ms.
ms.values Итерируемая коллекция, содержащая каждое значение, связанное с ключом из ms.
ms.valuesIterator Итератор, выдающий каждое значение, связанное с ключом из ms.
Преобразования:  
ms.view filterKeys p Отображение мапы, содержащее только те пары из ms, в которых ключ удовлетворяет предикату p.
ms.view mapValues f Представление мапы ms к значениям которой применена функция f.

Неизменяемые мапы поддерживают операции добавления и удаления элементов через возврат новых Мапов, как описано в следующей таблице.

Операции на Классе immutable.Map

ПРИМЕР ЧТО ДЕЛАЕТ
Добавления и обновления:  
ms.updated(k, v)
или ms + (k -> v)
Мапа, содержащая все пары из ms, а также ассоциативную связь k -> v от ключа k к значению v.
Удаления:  
ms remove k
или ms - k
Мапа, содержащая все пары ms за исключением пары с ключом k.
ms removeAll ks
или ms -- ks
Мапа, содержащая все пары из ms за исключением пары с ключом из ks.

Изменяемые мапы поддерживают дополнительные операции, которые представленным в таблице ниже.

Операции на Классе mutable.Map

ПРИМЕР ЧТО ДЕЛАЕТ
Добавления и обновления:  
ms(k) = v (либо эквивалент ms.update(x, v)). Добавляет связь от ключа k к значению v в мапе ms через побочный эффект, перезаписывая любую предыдущую связь с k.
ms.addOne(k -> v)
либо ms += (k -> v)
Добавляет связь от ключа k к значению v в мапе ms через побочный эффект и возвращает сам ms.
ms addAll xvs
либо ms ++= kvs
Добавляет все пары из kvs к ms через побочный эффект и возвращает сам ms.
ms.put(k, v) Добавляет связь от ключа k к значению v в мапе ms и возвращает любое значение, которое было ранее связанно с k (опционально).
ms getOrElseUpdate (k, d) Если ключ k определен на мапе ms, возвращает связанное с ним значение. В противном случае добавляет к ms связь вида k -> d и возвращает d.
Удаления:  
ms subtractOne k
либо ms -= k
Удаляет ассоциированную связь с ключом k из мапы ms побочным эффектом и возвращает сам ms.
ms subtractAll ks
либо ms --= ks
Удаляет все пары связанные с ключами ks из мапы ms побочным эффектом и возвращает сам ms.
ms remove k Удаляет любую пару связанную с ключом k из ms и возвращает значение, которое ранее было связанное с k (опционально).
ms filterInPlace p Оставляет только те пары в мапе ms, у которых ключ, удовлетворяет предикату p.
ms.clear() Удаляет все пары из мапы ms
Преобразования:  
ms mapValuesInPlace f Преобразует все значения в мапе ms используя функцию f.
Клонирования:  
ms.clone Возвращает новую изменяемую мапу с теми же парами, что и у ms.

Операции добавления и удаления в мапах совпадают с операциями добавления и удаления у множеств. Изменяемая мапа m обычно обновляется через замену значений в самой себе, используя два варианта синтаксиса m(key) = value или m += (key -> value). Существует также вариант m.put(key, value), который возвращает Option, содержащее значение, ранее связанного с key, или None, если key не было в мапе.

Функция getOrElseUpdate полезна для доступа к мапам, работающим в качестве кэша. Допустим, у вас есть дорогая для вычисления операция, вызываемая функцией f:

scala> def f(x: String) = {
       println("taking my time."); sleep(100)
       x.reverse }
f: (x: String)String

Допустим, что f без побочных эффектов, поэтому повторное обращение к функции с тем же аргументом всегда будет давать один и тот же результат. В этом случае можно сэкономить время, сохранив ранее вычисленное выражение связав аргумент с результатом f на мапе и вычислять f только в том случае, если результат для аргумента не находится в мапе. Можно сказать, что мапа представляет собой кэш для вычислений функции f.

scala> val cache = collection.mutable.Map[String, String]()
cache: scala.collection.mutable.Map[String,String] = Map()

Теперь вы можете создать более эффективную кэшированную версию функции f:

scala> def cachedF(s: String) = cache.getOrElseUpdate(s, f(s))
cachedF: (s: String)String
scala> cachedF("abc")
taking my time.
res3: String = cba
scala> cachedF("abc")
res4: String = cba

Обратите внимание, что второй аргумент для getOrElseUpdate вызывается “по имени”, поэтому вычисление f("abc") производится только если getOrElseUpdate запросит значения второго аргумента, точнее если его первый аргумент не найден в мапе cache. Вы могли бы реализовать cachedF самостоятельно, используя только базовые операции с мапами, но для этого понадобилось бы больше кода:

def cachedF(arg: String) = cache get arg match {
  case Some(result) => result
  case None =>
    val result = f(x)
    cache(arg) = result
    result
}

Contributors to this page: