Die Vereinigung zweier Karten in Gang bringen

80

Ich habe eine rekursive Funktion, die Objekte erstellt, die Dateipfade darstellen (die Schlüssel sind Pfade und die Werte sind Informationen über die Datei). Es ist rekursiv, da es nur für die Verarbeitung von Dateien gedacht ist. Wenn also ein Verzeichnis gefunden wird, wird die Funktion für das Verzeichnis rekursiv aufgerufen.

Abgesehen davon möchte ich das Äquivalent einer festgelegten Vereinigung auf zwei Karten ausführen (dh die "Haupt" -Karte, die mit den Werten aus dem rekursiven Aufruf aktualisiert wurde). Gibt es eine idiomatische Möglichkeit, dies zu tun, außer über eine Karte zu iterieren und jedem Schlüssel einen Wert zuzuweisen, der derselben Sache in der anderen Karte entspricht?

Das heißt: Da a,bsind vom Typ map [string] *SomeObjectund aund bschließlich besiedelt sind, ist es eine Möglichkeit, Update amit allen Werten in b?

jeffknupp
quelle
2
Vielleicht können Sie einen tatsächlichen Set-Container für diese Art von Arbeit verwenden: github.com/deckarep/golang-set
Ralph Caraveo
Ralphs Vorschlag ist gut für Sets. Ich würde jedoch sagen, dass es in Ihrem Fall weniger eine Gewerkschaft als vielmehr eine Fusion ist . Ein Satz sollte nur eine Sammlung von "Schlüsseln" sein, während Sie zwei Sammlungen von Schlüssel-Wert-Paaren haben, wobei ein "Satz" Vorrang vor dem anderen haben sollte.
ANisus

Antworten:

128

In den Standardpaketen gibt es weder eine integrierte Methode noch eine Methode, um eine solche Zusammenführung durchzuführen.

Der idomatische Weg besteht darin, einfach zu iterieren:

for k, v := range b {
    a[k] = v
}
ANisus
quelle
5
Um die Antwort von ANisus zu ergänzen: Karten sind im Wesentlichen Hash-Tabellen. Es gibt wahrscheinlich keine Möglichkeit, die Vereinigung zweier Karten schneller zu berechnen, als einfach über beide Karten zu iterieren.
Fuz
Sie könnten wahrscheinlich Reflexion verwenden, um eine typunabhängige Vereinigungsfunktion zu schreiben, aber sie wäre langsamer.
Evan
Sollte dieser Code nicht den Wert von a [k] und v UNIONEN, bevor v einem [k] zugewiesen wird? Was ist, wenn a [k] und v Arrays oder Maps sind?
Vdolez
2
Er versucht, die Karten zu vereinen, nicht unbedingt die Werte in den Karten. Wenn Sie so etwas tun möchten, müssen Sie nur a[k] = vzu a[k] = a[k] + voder so etwas wechseln .
Kyle
@ Kyle Ich denke du hast recht. Für die eigentliche Vereinigung kann dies verwendet werden:a[k] = append(a[k], v...)
user3405291
2

Wenn Sie ein paar verschachtelte Karten haben, leftund rightdann wird diese Funktion rekursiv die Elemente aus hinzufügen rightin left. Wenn der Schlüssel bereits vorhanden leftist, kehren wir tiefer in die Struktur zurück und versuchen, nur Schlüssel hinzuzufügenleft (z. B. niemals zu ersetzen).


type m = map[string]interface{}

// Given two maps, recursively merge right into left, NEVER replacing any key that already exists in left
func mergeKeys(left, right m) m {
    for key, rightVal := range right {
        if leftVal, present := left[key]; present {
            //then we don't want to replace it - recurse
            left[key] = mergeKeys(leftVal.(m), rightVal.(m))
        } else {
            // key not in left so we can just shove it in
            left[key] = rightVal
        }
    }
    return left
}

HINWEIS: Ich behandle nicht den Fall, in dem der Wert selbst nicht a ist map[string]interface{}. Also , wenn Sie left["x"] = 1und right["x"] = 2dann wird der obige Code in Panik , wenn versucht wird leftVal.(m).

JnBrymn
quelle