2012-03-22 16 views
5

Próbuję utworzyć zmienną wartość Map z wartością domyślną, która tworzy nowy ListBuffer, gdy żądany element nie znajduje się jeszcze na mapie. Jednakże, podczas gdy nowa mapa jest zwracana jako domyślna, nie pozostaje na mapie. Może tak to działa, pomyślałem, ale kiedy przetestowałem to z Int, a nie, zrobił dokładnie tak, jak chciałem. Oto kod, który wyjaśnia, co mam na myśli - co robię źle?Map withDefault pustego obiektu ListBuffer w scala

pierwsze, tu jest praca z 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) 

Teraz z 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)) 

Odpowiedz

3

Różnica jest taka:

W pierwszym przypadku a(2) jest Int . Ponieważ Int nie ma metody +=, a(2) += 1 jest równoważne a(2) = a(2) + 1 i tak do a.update(2, a(2) + 1). update faktycznie zmienia mapę.

Ale ListBuffer[Int]ma mieć metodę +=, więc rozmowa jest a(2).+=(1) i nie ustawisz a(2) do niczego!

+0

Świetnie, to ma sens - jak mogę to naprawić? Czy muszę to zrobić w trzech linijkach, pobierając element, dołączając do niego, a następnie ustawiając go ponownie? Ponieważ wolałbym tego unikać, jeśli to możliwe! – Russell

+0

Przypuszczam, że mogę zrobić mapę (i) = mapę (i) + = 5, ale wygląda całkiem nieźle. – Russell

+1

Tak, myślę, że tak (oczywiście, zawsze możesz wyodrębnić to do miłej metody pomocnika). –

1

Można użyć getOrElseUpdate(key: A, op: => B) gdzie można po prostu utworzyć nowe wystąpienie ListBuffer, gdy klucz nie jest obecny.

E.g.

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

+1 ponieważ chociaż może to być trochę irytujące i długotrwałe do napisania, intencja * jest dużo wyraźniejsza. – Russell

Powiązane problemy