Si realmente no necesita inmutabilidad, a continuación, como otros han dicho, MultiMap
es el camino a seguir. Si realmente necesitas inmutabilidad, entonces el enfoque que has tomado es tan fácil como cualquier otra cosa; no hay nada incorporado (AFAIK), y cualquier creación de un MultiMap inmutable requerirá mucho más trabajo que el método que tienes allí.
Si la representación es superior depende de su uso. ¿A menudo quieres hacer cosas con todos los valores correspondientes a una tecla? ¿Puedes insertar el mismo valor varias veces en tu mapa? Si es así para ambos, su representación es la correcta.
Si desea que el mismo valor insertado como máximo una vez en una llave, se debe usar en lugar de Set[U]
Iterable[U]
(que se puede hacer fácilmente mediante la adición de .toSet
-it.map(_._2)
).
Si no te gusta tener que lidiar con sets/iterables y solo lo estás soportando (es decir, prefieres tener pares clave-valor que pares key-setofvalues), deberías escribir una clase contenedora alrededor del mapa que presenta una única interfaz de mapa y haría lo correcto con +, -, e iterador.
Aquí hay un ejemplo que resultó un poco más de lo que había anticipado (en este formato para cortar y pegar en el REPL):
import scala.collection._
class MapSet[A,B](
val sets: Map[A,Set[B]] = Map[A,Set[B]]()
) extends Map[A,B] with MapLike[A,B,MapSet[A,B]] {
def get(key: A) = sets.getOrElse(key,Set[B]()).headOption
def iterator = new Iterator[(A,B)] {
private val seti = sets.iterator
private var thiskey:Option[A] = None
private var singles:Iterator[B] = Nil.iterator
private def readyNext {
while (seti.hasNext && !singles.hasNext) {
val kv = seti.next
thiskey = Some(kv._1)
singles = kv._2.iterator
}
}
def hasNext = {
if (singles.hasNext) true
else {
readyNext
singles.hasNext
}
}
def next = {
if (singles.hasNext) (thiskey.get , singles.next)
else {
readyNext
(thiskey.get , singles.next)
}
}
}
def +[B1 >: B](kv: (A,B1)):MapSet[A,B] = {
val value:B = kv._2.asInstanceOf[B]
new MapSet(sets + ((kv._1 , sets.getOrElse(kv._1,Set[B]()) + value)))
}
def -(key: A):MapSet[A,B] = new MapSet(sets - key)
def -(kv: (A,B)):MapSet[A,B] = {
val got = sets.get(kv._1)
if (got.isEmpty || !got.get.contains(kv._2)) this
else new MapSet(sets + ((kv._1 , got.get - kv._2)))
}
override def empty = new MapSet(Map[A,Set[B]]())
}
y podemos ver que esto funciona como se desea de este modo:
scala> new MapSet() ++ List(1->"Hi",2->"there",1->"Hello",3->"Bye")
res0: scala.collection.Map[Int,java.lang.String] = Map(1 -> Hi, 1 -> Hello, 2 -> there, 3 -> Bye)
scala> res0 + (2->"ya")
res1: scala.collection.Map[Int,java.lang.String] = Map(1 -> Hi, 1 -> Hello, 2 -> there, 2 -> ya, 3 -> Bye)
scala> res1 - 1
res2: scala.collection.Map[Int,java.lang.String] = Map(2 -> there, 2 -> ya, 3 -> Bye)
(aunque si quisieras recuperar un MapSet después de ++, necesitarías anular ++; la jerarquía de Mapas no tiene sus propios creadores para encargarse de cosas como esta).
Bueno, no puedo pensar en ninguna forma de mejorar lo que tienes. –