2012-03-22 5 views
5

Estoy tratando de crear un Map mutable con un valor predeterminado que crea un nuevo ListBuffer cuando se solicita un elemento que no está ya en el mapa. Sin embargo, aunque el nuevo mapa se devuelve como predeterminado, no permanece en el mapa. Quizás así es como funciona, pensé, pero cuando lo probé con un Int en lugar de un ListBuffer, hice exactamente lo que quería. Aquí hay un código para explicar a qué me refiero: ¿qué estoy haciendo mal?Map withDefault de un ListBuffer vacío en scala

primer lugar, aquí se está trabajando con un Map[Int]:

scala> val a = collection.mutable.Map(1 -> 1).withDefault(i => 0) 
a: scala.collection.mutable.Map[Int,Int] = Map(1 -> 1) 

scala> a(1) += 1 // adding to an existing element works as expected 

scala> a 
res48: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2) 

scala> a(2) += 1 // what about adding to a non-existing element? 

scala> a // the new element has been added to the map 
res50: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2, 2 -> 1) 

Ahora con un Map[ListBuffer[Int]]:

scala> val b = collection.mutable.Map(1 -> collection.mutable.ListBuffer[Int]()).withDefault(i => collection.mutable.ListBuffer.empty[Int]) 
b: scala.collection.mutable.Map[Int,scala.collection.mutable.ListBuffer[Int]] = Map(1 -> ListBuffer()) 

scala> b(1) += 1 // appending to an existing element works as expected 
res51: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1) 

scala> b 
res52: scala.collection.mutable.Map[Int,scala.collection.mutable.ListBuffer[Int]] = Map(1 -> ListBuffer(1)) 

scala> b(2) += 1 // but appending to a non-existing element... 
res53: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1) 

scala> b // leaves the map unchanged 
res54: scala.collection.mutable.Map[Int,scala.collection.mutable.ListBuffer[Int]] = Map(1 -> ListBuffer(1)) 

Respuesta

3

La diferencia es la siguiente:

En el primer caso a(2) es un Int . Como Int no tiene un método +=, a(2) += 1 es equivalente a a(2) = a(2) + 1 y, por lo tanto, a a.update(2, a(2) + 1). El update realmente cambia el mapa.

Pero ListBuffer[Int] qué tienen un método +=, por lo que su llamada es a(2).+=(1), y no establece a(2) a nada!

+0

Genial, eso tiene sentido, entonces, ¿cómo puedo solucionarlo? ¿Tengo que hacerlo en tres líneas, obtener el elemento, adjuntarlo y luego volver a configurarlo? ¡Porque prefiero evitar eso si es posible! – Russell

+0

Supongo que puedo hacer map (i) = map (i) + = 5 pero parece bastante malo. – Russell

+1

Sí, creo que sí (por supuesto, siempre puedes extraer esto en un buen método de ayuda). –

1

Puede usar getOrElseUpdate(key: A, op: => B) donde puede simplemente crear una nueva instancia de ListBuffer, cuando la clave no está presente.

E.g.

val m = collection.mutable.Map[Int, ListBuffer[Int]]() 
m.getOrElseUpdate(1, ListBuffer()) += 1 
+0

+1 porque aunque puede ser un poco irritante y prolijo escribir, la * intención * es mucho más clara. – Russell

Cuestiones relacionadas