2012-03-22 12 views
5

Sto tentando di creare un Map mutabile con un valore predefinito che crea un nuovo ListBuffer quando viene richiesto un elemento che non è già nella mappa. Tuttavia, mentre la nuova mappa viene restituita come predefinita, non rimane nella mappa. Forse è proprio così che funziona, ho pensato, ma quando l'ho testato con uno Int anziché con uno ListBuffer ha fatto esattamente quello che volevo. Ecco un codice per spiegare cosa intendo - cosa sto sbagliando?Mappa con Default di un ListBuffer vuoto in scala

In primo luogo, qui si sta lavorando 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) 

Ora, 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)) 

risposta

3

La differenza è questa:

Nel primo caso a(2) è un Int . Poiché Int non ha un metodo +=, a(2) += 1 equivale a a(2) = a(2) + 1 e quindi a a.update(2, a(2) + 1). Lo update modifica effettivamente la mappa.

Ma ListBuffer[Int]fa hanno un metodo di +=, quindi la chiamata viene a(2).+=(1), e non si imposta a(2) a nulla!

+0

Grande, questo ha senso, quindi come posso risolverlo? Devo farlo su tre righe, ottenere l'elemento, accodarlo, quindi ripristinarlo? Perché preferirei evitarlo, se possibile! – Russell

+0

Suppongo di poter fare map (i) = map (i) + = 5 ma sembra piuttosto schifoso. – Russell

+1

Sì, penso di sì (ovviamente, puoi sempre estrarlo in un bel metodo di supporto). –

1

È possibile utilizzare getOrElseUpdate(key: A, op: => B) in cui è possibile creare una nuova istanza di ListBuffer quando la chiave non è presente.

E.g.

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

+1 perché mentre questo può essere un po 'irritante e prolisso per scrivere, l'intento * è molto più chiaro. – Russell