Неизменяемые и изменяемые коллекции
Вам нужно выбрать , какой тип коллекции вы будете использовать immutable
или mutable
один. Оба великолепны и работают совершенно по-разному . Я предполагаю, что вы знакомы с mutable
one (из других языков), но immutable
по умолчанию в scala и, вероятно, вы используете его в своем коде (потому что он не нуждается в импорте). Неизменяемое Map
не может быть изменено ... вы можете создать только новое с обновленными значениями (ответы Тима и Ивана охватывают это).
Есть несколько способов решить вашу проблему, и все хорошо в зависимости от варианта использования .
См. Реализацию ниже (от m1 до m6):
//just for convenience
type T = String
type E = Long
import scala.collection._
//immutable map with immutable seq (default).
var m1 = immutable.Map.empty[T,List[E]]
//mutable map with immutable seq. This is great for most use-cases.
val m2 = mutable.Map.empty[T,List[E]]
//mutable concurrent map with immutable seq.
//should be fast and threadsafe (if you know how to deal with it)
val m3 = collection.concurrent.TrieMap.empty[T,List[E]]
//mutable map with mutable seq.
//should be fast but could be unsafe. This is default in most imperative languages (PHP/JS/JAVA and more).
//Probably this is what You have tried to do
val m4 = mutable.Map.empty[T,mutable.ArrayBuffer[E]]
//immutable map with mutable seq.
//still could be unsafe
val m5 = immutable.Map.empty[T,mutable.ArrayBuffer[E]]
//immutable map with mutable seq v2 (used in next snipped)
var m6 = immutable.Map.empty[T,mutable.ArrayBuffer[E]]
//Oh... and NEVER DO THAT, this is wrong
//I mean... don't keep mutable Map in `var`
//var mX = mutable.Map.empty[T,...]
Другие ответы показывают immutable.Map
с immutable.Seq
, и это предпочтительный способ (или, по крайней мере, по умолчанию). Это стоит чего-то, но для большинства приложений это совершенно нормально. Здесь у вас есть хороший источник информации о неизменных структурах данных: https://stanch.github.io/reftree/talks/Immutability.html.
Каждый вариант имеет свои плюсы и минусы. Каждый имеет дело с обновлениями по-своему, и это делает этот вопрос намного сложнее, чем выглядит на первый взгляд.
Решения
val k = "The Ultimate Answer"
val v = 42f
//immutable map with immutable seq (default).
m1 = m1.updated(k, v :: m1.getOrElse(k, Nil))
//mutable map with immutable seq.
m2.update(k, v :: m2.getOrElse(k, Nil))
//mutable concurrent map with immutable seq.
//m3 is bit harder to do in scala 2.12... sorry :)
//mutable map with mutable seq.
m4.getOrElseUpdate(k, mutable.ArrayBuffer.empty[Float]) += v
//immutable map with mutable seq.
m5 = m5.updated(k, {
val col = m5.getOrElse(k, c.mutable.ArrayBuffer.empty[E])
col += v
col
})
//or another implementation of immutable map with mutable seq.
m6.get(k) match {
case None => m6 = m6.updated(k, c.mutable.ArrayBuffer(v))
case Some(col) => col += v
}
проверьте scalafiddle с этими реализациями. https://scalafiddle.io/sf/WFBB24j/3. Это отличный инструмент (ps: вы всегда можете сохранить CTRL+S
ваши изменения и поделиться ссылкой, чтобы написать вопрос о вашем фрагменте).
О ... и если Вас интересует параллелизм (m3
case), напишите другой вопрос. Такие топи c заслуживают того, чтобы быть в отдельном потоке:)
(im) изменяемые коллекции API (im) изменяемые коллекции
Вы можете иметь изменяемая коллекция и все еще использовать неизменный API, который будет копировать оригинальную последовательность . Например, Array
является изменяемым:
val example = Array(1,2,3)
example(0) = 33 //edit in place
println(example.mkString(", ")) //33, 2, 3
Но некоторые функции на нем (например, ++
) создадут новую последовательность ... не изменит существующую:
val example2 = example ++ Array(42, 41) //++ is immutable operator
println(example.mkString(", ")) //33, 2, 3 //example stays unchanged
println(example2.mkString(", ")) //33, 2, 3, 42, 41 //but new sequence is created
Там метод updateWith
, который является изменяемым и будет существовать только в изменяемых последовательностях . Существует также updatedWith
, и он существует как в неизменяемых, так и в изменяемых коллекциях, и если вы не будете достаточно осторожны, вы будете использовать неправильную (да ... еще 1 буква).
This означает, что вы должны быть осторожны, какие функции вы используете, неизменяемые или изменяемые. Большую часть времени вы можете различать их по типу результата. Если что-то возвращает коллекцию, то, вероятно, это будет какая-то копия оригинального seq. Результатом является единица, тогда оно непостоянно.