Uruchamiam połączenie dwóch map

82

Mam funkcję rekurencyjną, która tworzy obiekty reprezentujące ścieżki plików (klucze to ścieżki, a wartości to informacje o pliku). Jest rekurencyjna, ponieważ jest przeznaczona tylko do obsługi plików, więc jeśli napotkany zostanie katalog, funkcja jest rekurencyjnie wywoływana w katalogu.

Biorąc to wszystko pod uwagę, chciałbym zrobić odpowiednik set union na dwóch mapach (tj. Mapa „główna” zaktualizowana wartościami z wywołania rekurencyjnego). Czy istnieje idiomatyczny sposób na zrobienie tego poza iteracją po jednej mapie i przypisaniem każdemu kluczowi, wartości w nim tej samej rzeczy na drugiej mapie?

Czyli: podane a,bsą typu map [string] *SomeObject, a ai bsą ostatecznie zaludnionych, czy jest jakiś sposób na aktualizację aze wszystkimi wartościami b?

jeffknupp
źródło
2
Być może przydasz się
Ralph Caraveo
Sugestia Ralpha jest dobra w przypadku zestawów. Jednakże powiedziałbym, że w twoim przypadku jest to nie tyle związek, co fuzja ; zbiór powinien być po prostu zbiorem „kluczy”, podczas gdy mamy dwie kolekcje par klucz-wartość, z których jeden „zestaw” powinien mieć pierwszeństwo przed drugim.
ANisus,

Odpowiedzi:

133

W standardowych pakietach nie ma wbudowanego sposobu ani żadnej metody na wykonanie takiego scalenia.

Idomatycznym sposobem jest po prostu iteracja:

for k, v := range b {
    a[k] = v
}
ANisus
źródło
5
Aby dodać do tego, na co odpowiedział ANisus: Mapy są zasadniczo tablicami skrótów. Prawdopodobnie nie ma sposobu na szybsze obliczenie sumy dwóch map niż po prostu iteracja po obu mapach.
fuz
Prawdopodobnie mógłbyś użyć odbicia do napisania funkcji unii niezależnej od typu, ale byłoby to wolniejsze.
Evan,
Czy ten kod UNION nie powinien mieć wartości a [k] i v przed przypisaniem v do a [k]? A jeśli a [k] i v są tablicami lub mapami?
vdolez
2
Chce połączyć mapy, niekoniecznie wartości na mapach. Jeśli chcesz zrobić coś takiego, po prostu musisz zmienić a[k] = vna a[k] = a[k] + vlub coś takiego.
Kyle,
@Kyle Myślę, że masz rację. W przypadku rzeczywistej unii można użyć tego:a[k] = append(a[k], v...)
user3405291
2

Jeśli masz kilka zagnieżdżonych map lefti right, ta funkcja będzie rekurencyjnie dodawać elementy z rightdo left. Jeśli klucz jest już w leftśrodku, sięgamy głębiej do struktury i próbujemy tylko dodawać klucze left(np. Nigdy ich nie zastępować).


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
}

UWAGA: nie zajmuję się przypadkiem, w którym sama wartość nie jest a map[string]interface{}. Więc jeśli masz, left["x"] = 1a right["x"] = 2powyższy kod będzie panikować podczas próby leftVal.(m).

JnBrymn
źródło