2015-02-07 3 views
7

Ich weiß über einige ähnliche Fragen. Sie helfen mir nicht - Code funktioniert nicht, wenn kein Schlüssel vorhanden ist.Schöne Möglichkeit, Nummer zu Element in Scala Karte hinzufügen, wenn der Schlüssel existiert oder ein neues Element einfügen es nicht

Ich brauche nur einen netten Ansatz, um Map mit Wert hinzuzufügen, den bestehenden Schlüssel (falls vorhanden) hinzuzufügen oder als NEUEN Schlüssel zu setzen (wenn die Karte keinen passenden Schlüssel enthält).

Code funktioniert Nach aber ich mag es nicht:

val a = collection.mutable.Map(("k1" -> 1), ("k2" -> 5)) 
val key = "k1" 

val elem = a.get(key) 
if (elem == None) { 
    a += ("k5" -> 200) 
} else { 
    a.update(key, elem.get + 5) 
} 

Jeder Punkt auf bessere? Aktuelle Scala-Version ist 2.10.4 und ich kann derzeit nicht auf 2.11 wechseln. Veränderbare Map ist keine 100% Beschränkung, wird aber bevorzugt.

Hier ist zum Beispiel similar question, aber ich muss auch den Fall eines nicht vorhandenen Schlüssels berücksichtigen, der dort nicht berücksichtigt wird. Zumindest sollten wir verstehen, a.get(key) könnte None sein oder einen besseren Ansatz hinzufügen. Gute Idee war |+|, aber ich möchte grundlegende Scala 2.10.x behalten.

Antwort

6

Sie können Sie eigene Funktion zu diesem Zweck erstellen:

def addOrUpdate[K, V](m: collection.mutable.Map[K, V], k: K, kv: (K, V), 
         f: V => V) { 
    m.get(k) match { 
    case Some(e) => m.update(k, f(e)) 
    case None => m += kv 
    } 
} 

addOrUpdate(a, "k1", "k5" -> 200, (v: Int) => v + 5) 
+1

Wahrscheinlich für jetzt ist es die beste Option. Aber WARUM Scala anspruchsvolle Container-Bibliothek kann nicht so einfach aus der Box bieten - mit Schlüssel und Wert entweder Wert hinzufügen (wenn kein Schlüssel existiert) oder etwas mit sowohl aktuellen Wert und meine eine? Das nächste Mal wird dies definitiv zumindest in die Unternehmensbibliothek (Teufel) aufgenommen. –

+5

Das ist sehr seltsam IMHO: Hinzufügen eines Schlüssels, wenn ein ** anderes ** ist nicht vorhanden ist nicht wirklich ein Mainstream-Verhalten –

+1

Warum? Zum Beispiel möchte ich die Aggregation nach Schlüssel als Map erstellen und ich muss Elemente einzeln hinzufügen, so dass Dinge wie 'reduce()' nicht verwendet werden können? –

7

Der kürzeste Weg, das zu tun:

a += a.get(key).map(x => key -> (x + 5)).getOrElse("k5" -> 200) 

Allgemein gilt:

a += a.get(k).map(f).map(k -> _).getOrElse(kv) 

Same, wenn Ihr Wörterbuch ist unveränderlich:

m + m.get(k).map(f).map(k -> _).getOrElse(kv) 

so sehe ich keinen Grund, hier Mutable Sammlung zu verwenden.

Wenn Sie nicht alle diese Option.map Dinge wie:

m + (if (m.contains(k)) k -> f(m(k)) else kv) 

Hinweis, dass es eine ganze Klasse von möglichen Variationen ist:

k1 -> f(m(k1)) else k2 -> v2 //original 
k1 -> f(m(k1)) else k1 -> v2 
k1 -> f(m(k2)) else k2 -> v2 
k1 -> f(m(k2)) else k1 -> v2 
k2 -> v2 else k1 -> f(m(k1)) 
k1 -> v2 else k1 -> f(m(k1)) 
k2 -> v2 else k1 -> f(m(k2)) 
k1 -> v2 else k1 -> f(m(k2)) 
... //v2 may also be a function from some key's value 

Also, warum es ist keine Standardfunktion? IMO, weil alle Varianten immer noch als Einzeiler umgesetzt werden können. Wenn Sie eine Bibliothek mit allen Funktionen möchten, die als One-Liner implementiert werden können, wissen Sie, es ist Scalaz :).

P.S. Wenn yu frage mich auch, warum es keine "Update (d) wenn anhalten" ist Funktion - siehe @Rex Kerr ‚s Antwort here

1

Eine irgendwie klar Weg, dies zu tun:

val a = collection.mutable.Map[String, Int]() withDefault insertNewValue 

def insertNewValue(key: String): Int = 
    a += key -> getValueForKey(key) 
    a(key) 
} 

def getValueForKey(key: String): Int = key.length 

Trotzdem bin total disencourage die Verwendung von veränderbaren Sammlungen. Es ist vorzuziehen, den internen veränderbaren Status als Variablen zu behalten, die unveränderliche Felder enthalten.

Dies ist wegen einer einfachen Regel, sollten Sie nicht Ihren inneren Zustand aussetzen, es sei denn, es ist völlig notwendig, und wenn Sie dies tun, sollten Sie so weit wie möglich die möglichen Nebenwirkungen verringern, die möglicherweise produzieren.

Wenn Sie einen Verweis auf einen veränderbaren Status bereitstellen, kann jeder andere Akteur seine Werte ändern, wodurch die referenzielle Transparenz verloren geht.Es ist kein Zufall, dass alle Verweise auf veränderbare Sammlungen ziemlich lang und schwierig zu verwenden sind. Das ist eine Botschaft der Entwickler für Sie

nicht überraschend, der Code immer noch die gleiche bleibt, wobei einige minimale Änderungen an der Karte Instanziierung.

var a = Map[String, Int]() withDefault insertNewValue 

def insertNewValue(key: String): Int = { 
    a += key -> getValueForKey(key) 
    a(key) 
} 

def getValueForKey(key: String): Int = key.length 
Verwandte Themen