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?



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
}

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).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.