2010-09-06 6 views
29

Mam zmienną mapę HashMap i chciałbym użyć jej jako domyślnego słownika. Oczywistą metodą wydaje się być użycie getOrElse i podanie wartości domyślnej za każdym razem jako drugiej wartości. Wydaje się to jednak trochę nieeleganckie w moim przypadku użycia, ponieważ domyślna wartość nie zmienia się.Scala: Używanie HashMap z domyślną wartością

var x = HashMap(1 -> "b", 2 -> "a", 3 -> "c") 

println(x.getOrElse(4, "_") 
println(x.getOrElse(5, "_")) 
// And so on... 
println(x.getOrElse(10, "_")) 

Czy istnieje jakiś sposób, aby utworzyć HashMap (lub podobnej klasy) taką, że próbujesz uzyskać dostęp do niezdefiniowanych kluczy zwraca wartość domyślną ustawioną na stworzeniu HashMap? Zauważyłem, że HashMap.default jest po prostu ustawiona na wyjątek, ale zastanawiam się, czy można to zmienić ...

+5

Do każdego, kto natyka się na to pytanie, po missingfaktor za słusznie stwierdza, że ​​ „Scala 2.9.1 mutable.Map pochodzi z metody withDefaultValue.” – wynnch

Odpowiedz

34

Spróbuj tego:

import collection.mutable.HashMap 
val x = new HashMap[Int,String]() { override def default(key:Int) = "-" } 
x += (1 -> "b", 2 -> "a", 3 -> "c") 

Następnie:

scala> x(1) 
res7: String = b 

scala> x(2) 
res8: String = a 

scala> x(3) 
res9: String = c 

scala> x(4) 
res10: String = - 
+4

+1. Zastanawiam się, dlaczego 'mutable.HashMap' nie udostępnia metody' withDefaultValue' takiej jak 'immutable.HashMap'. – missingfaktor

+2

To okropna składnia, ale to wystarczy. Być może brak parametru withDefaultValue dla zmiennych HashMaps powinien zostać zgłoszony jako błąd? –

+4

Istnieje "!!! todo: przenieść na mapy ogólne?" komentarz w sąsiednim 'withDefault' w http://www.scala-lang.org/api/current/scala/collection/immutable/Map.html. Więc może to nie jest zbyt wiele.Lista mailingowa scala-user jest prawdopodobnie dobrym miejscem, aby zapytać o to i sprawdzić, czy błąd powinien zostać zgłoszony. – huynhjl

1
scala> val x = HashMap(1 -> "b", 2 -> "a", 3 -> "c").withDefaultValue("-") 
x: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,b), (2,a), (3,c)) 

scala> x(3) 
res0: java.lang.String = c 

scala> x(5) 
res1: java.lang.String = - 

EDIT:

Dla mutable.HashMap, można wykonać następujące czynności:

scala> import collection.mutable 
import collection.mutable 

scala> val x = new mutable.HashMap[Int, String] { 
    | override def apply(key: Int) = super.get(key) getOrElse "-" 
    | } 
x: scala.collection.mutable.HashMap[Int,String] = Map() 

scala> x += (1 -> "a", 2 -> "b", 3 -> "c") 
res9: x.type = Map((2,b), (1,a), (3,c)) 

scala> x(2) 
res10: String = b 

scala> x(4) 
res11: String = - 

Może istnieć lepszy sposób na zrobienie tego. Zaczekaj, aż inni zareagują.

+0

który pojawia się tylko do pracy z niezmiennymi HashMaps. –

+1

@PythonPower: Nie określiłeś tego w oryginalnym pytaniu, że używasz 'mutable.HashMap'. Nie wiem jak to zrobić z 'mutable.HashMap'. Będę musiał zajrzeć do API. – missingfaktor

+0

Tak, przepraszam, nie sprecyzowałem - zredagowałem moje pytanie, aby teraz było jasne. –

0

jestem bardziej java facet ... ale jeśli getOrElse nie jest ostateczna, dlaczego nie można po prostu rozszerzyć HasMap i dostarczyć coś takiego:

override def getOrElse(k: Int, default: String) = { 
    return super.getOrElse(k,"_") 
} 

Uwaga: Składnia jest prawdopodobnie wkręca się jednak mam nadzieję, że dostaniesz punkt

+0

Tak, myślę, że możliwe jest rozszerzenie HashMap. W takim przypadku łatwiej byłoby zmienić metodę HashMap.default, aby zwrócić to, co chcę. Konstruktor może przyjąć wartość domyślną, a metoda HashMap.default po prostu to zwróci. Mam jednak nadzieję, że istnieje łatwiejsza metoda. –

+0

Nie robimy tego bc jest bardziej skomplikowany niż 'getOrElse' - ma mniejszą elastyczność, jest niepotrzebnie gęsty, a jeśli * musisz * to zrobić, jest silnym wskazaniem, że powinieneś używać abstrakcji wysokiego poziomu, jak monoidy . – BAR

67

Wow, przypadkiem odwiedziłem ten wątek dokładnie rok po opublikowaniu ostatniej odpowiedzi tutaj. :-)

Scala 2.9.1. mutable.Map pochodzi z metody withDefaultValue. REPL sesja:

scala> import collection.mutable 
import collection.mutable 

scala> mutable.Map[Int, String]().withDefaultValue("") 
res18: scala.collection.mutable.Map[Int,String] = Map() 

scala> res18(3) 
res19: String = "" 
+0

To powinno być oznaczone jako poprawna odpowiedź –

+0

Jestem zaniepokojony wydajnością tego - czy zmienia się. Czy mapy HashMaps są używane? Jaka jest jego wydajność? –