Отримання об’єднання двох карт в go


81

У мене є рекурсивна функція, яка створює об'єкти, що представляють шляхи до файлів (ключі - це шляхи, а значення - інформація про файл). Він є рекурсивним, оскільки призначений лише для обробки файлів, тому, якщо зустрічається каталог, функція викликається в каталозі рекурсивно.

Все сказане, я хотів би зробити еквівалент набору об'єднань на двох картах (тобто "основна" карта, оновлена ​​значеннями з рекурсивного виклику). Чи є ідіоматичний спосіб зробити це, крім перебору однієї карти та присвоєння кожному ключу, значення в ній тому самому на іншій карті?

Тобто: дані a,bмають тип map [string] *SomeObject, aі b, зрештою, заповнюються, чи є спосіб оновитиa з усіма значеннями в b?


2
Можливо, ви можете використовувати фактичний набір контейнерів для цього виду роботи: github.com/deckarep/golang-set
Ральф Каравео

Пропозиція Ральфа хороша для наборів. Однак я б сказав, що у вашому випадку це не стільки союз, скільки злиття ; набір повинен бути просто колекцією "ключів", тоді як у вас є дві колекції пар ключ-значення, де один "набір" повинен мати пріоритет над іншим.
ANisus

Відповіді:


132

Немає вбудованого способу та жодного методу у стандартних пакетах для здійснення такого злиття.

Ідоматичний спосіб - це просто повторити:

for k, v := range b {
    a[k] = v
}

5
Щоб додати до того, що відповів ANisus: Карти, по суті, є хеш-таблицями. Ймовірно, немає жодного способу обчислити об’єднання двох карт швидше, ніж просто ітерація по обох картах.
fuz

Можливо, ви могли б використовувати відображення для написання функції агностичного об'єднання типу, але це було б повільніше.
Еван

Чи не повинен цей код ОБ'ЄДНАТИ значення a [k] та v перед тим, як присвоювати v a [k]? Що робити, якщо a [k] та v - це масиви або карти?
vdolez

2
Він прагне об'єднати карти, не обов'язково значення на картах. Якщо ви хочете зробити щось подібне, вам просто потрібно перейти a[k] = vна a[k] = a[k] + vщось подібне.
Кайл

@Kyle Я думаю, ти маєш рацію. Для фактичного об'єднання це можна використовувати:a[k] = append(a[k], v...)
user3405291

2

Якщо у вас є кілька вкладених карт leftі right, тоді ця функція буде рекурсивно додавати елементи з rightв left. Якщо ключ уже leftвведений, ми повторюємо глибше структуру і намагаємось лише додати ключі до left(наприклад, ніколи не замінювати їх).


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
}

ПРИМІТКА: Я не розглядаю справи, в яких значення не є самим собою map[string]interface{}. Так що якщо у вас є left["x"] = 1і right["x"] = 2те вище код буде панікувати при спробі leftVal.(m).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.