Как преобразовать immutable.Map в mutable.Map в Scala?

Как преобразовать immutable.Map в mutable.Map в Scala, чтобы обновить значения в Map?


person Łukasz Lew    schedule 18.02.2011    source источник


Ответы (6)


Самым чистым способом было бы использовать фабрику mutable.Map varargs. В отличие от подхода ++ здесь используется механизм CanBuildFrom, и поэтому он может быть более эффективным, если код библиотеки будет написан с учетом этого:

val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m.toSeq: _*) 

Это работает, потому что Map также можно рассматривать как последовательность пар.

person Kevin Wright    schedule 19.02.2011
comment
Можете объяснить, какой синтаксис вы используете во второй строке при передаче параметра? Что делает толстая кишка? - person Heinzi; 01.06.2012
comment
: _* очень похоже на приписывание типа, сообщая компилятору, какой именно тип следует присвоить данному выражению. Вы можете думать об этом здесь как о том, чтобы взять эту последовательность и рассматривать ее как ряд параметров vararg. - person Kevin Wright; 06.06.2012
comment
Что-то не так с библиотеками коллекций, если это самое чистое;) - person matanster; 08.11.2015
comment
@matt Его можно было бы сделать немного короче с помощью импорта с псевдонимами, но имейте в виду, что жертвование неизменностью очень неидиоматично для Scala, а не совсем то, что я бы поощрял, делая его ровным. проще... Из любопытства, как еще можно предложить сделать это более чисто, если не через копию? - person Kevin Wright; 09.11.2015
comment
Это моя точка зрения, я не могу, но лучшая библиотека коллекций может сделать это возможным, ИМХО. - person matanster; 09.11.2015

Начиная с Scala 2.13, с помощью заводских сборщиков, применяемых с .to(factory):

Map(1 -> "a", 2 -> "b").to(collection.mutable.Map)
// collection.mutable.Map[Int,String] = HashMap(1 -> "a", 2 -> "b")
person Xavier Guihot    schedule 30.06.2019

Как насчет использования collection.breakOut?

import collection.{mutable, immutable, breakOut}
val myImmutableMap = immutable.Map(1->"one",2->"two")
val myMutableMap: mutable.Map[Int, String] = myImmutableMap.map(identity)(breakOut)
person ymnk    schedule 18.02.2011
comment
Это это круто, но в основном делает то же самое, что и mutable.Map#apply, но с немного большим количеством шаблонов. - person Kevin Wright; 20.02.2011

Существует вариант создания пустого изменяемого Map со значениями по умолчанию, взятыми из неизменяемого Map. Вы можете сохранить значение и переопределить значение по умолчанию в любое время:

scala> import collection.immutable.{Map => IMap}
//import collection.immutable.{Map=>IMap}

scala> import collection.mutable.HashMap
//import collection.mutable.HashMap

scala> val iMap = IMap(1 -> "one", 2 -> "two")
//iMap: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,one), (2,two))

scala> val mMap = new HashMap[Int,String] {      
     | override def default(key: Int): String = iMap(key)
     | }
//mMap: scala.collection.mutable.HashMap[Int,String] = Map()

scala> mMap(1)
//res0: String = one

scala> mMap(2)
//res1: String = two

scala> mMap(3)
//java.util.NoSuchElementException: key not found: 3
//  at scala.collection.MapLike$class.default(MapLike.scala:223)
//  at scala.collection.immutable.Map$Map2.default(Map.scala:110)
//  at scala.collection.MapLike$class.apply(MapLike.scala:134)
//  at scala.collection.immutable.Map$Map2.apply(Map.scala:110)
//  at $anon$1.default(<console>:9)
//  at $anon$1.default(<console>:8)
//  at scala.collection.MapLike$class.apply(MapLike.scala:134)....

scala> mMap(2) = "three"

scala> mMap(2)          
//res4: String = three

Предостережение (см. комментарий Рекса Керра): вы не сможете удалить элементы из неизменяемой карты:

scala> mMap.remove(1)
//res5: Option[String] = None

scala> mMap(1)
//res6: String = one
person Alexander Azarov    schedule 18.02.2011
comment
В некоторых случаях это полезно, но учтите, что вы не можете удалить элемент на новой карте, который присутствовал на карте по умолчанию; вы можете только закрывать и раскрывать значения по умолчанию. - person Rex Kerr; 18.02.2011
comment
Правильно, это решение частичное. - person Alexander Azarov; 19.02.2011

В scala 2.13 есть две альтернативы: метод to экземпляра исходной карты или метод from объекта-компаньона целевой карты.

scala> import scala.collection.mutable
import scala.collection.mutable

scala> val immutable = Map(1 -> 'a', 2 -> 'b');
val immutable: scala.collection.immutable.Map[Int,Char] = Map(1 -> a, 2 -> b)

scala> val mutableMap1 = mutable.Map.from(immutable)
val mutableMap1: scala.collection.mutable.Map[Int,Char] = HashMap(1 -> a, 2 -> b)

scala> val mutableMap2 = immutable.to(mutable.Map)
val mutableMap2: scala.collection.mutable.Map[Int,Char] = HashMap(1 -> a, 2 -> b)

Как видите, реализация mutable.Map была выбрана библиотекой. Если вы хотите выбрать конкретную реализацию, например mutable.HashMap, замените все вхождения mutable.Map на mutable.HashMap.

person Readren    schedule 10.10.2020

person    schedule
comment
Вы знаете, что такое асимптотическая временная сложность? Я знаю, что Clojure может превратить любую из своих постоянных коллекций во временную (то есть изменяемую с линейно типизированными функциями мутации) и обратно в постоянную за O(1) шагов. Это выглядит как O(n), хотя это, конечно, зависит от того, насколько умна реализация ++. - person Jörg W Mittag; 18.02.2011
comment
@ Йорг - я почти уверен, что это O(n). В пределе, когда вы меняете все, это должно быть O(n), хотя вы можете попробовать отложить создание новой копии, чтобы сэкономить время, или удвоить время доступа, читая наборы изменений вместо исходной карты. Какой из них работает лучше всего, вероятно, зависит от вашего варианта использования. - person Rex Kerr; 18.02.2011
comment
@Rustem - Карты неупорядочены. Они будут отображаться в том порядке, в котором они хотят (с хеш-картой это обычно порядок хеш-ключа). В частности, неизменяемые карты имеют особые случаи для действительно крошечных карт, которые отличаются от изменяемых карт. - person Rex Kerr; 18.02.2011
comment
@Rustem Карты не упорядочены. - person Daniel C. Sobral; 18.02.2011