Слияние карт в Голанге - PullRequest
0 голосов
/ 14 мая 2018

Мне нужно объединить несколько карт map1 = [ id: id_1 val: val_1 ], map2 = [ id: id_2 val: val_2 ] и map3 = [id: id_1, val: val_3] так, чтобы карта результатов была объединена со значениями id:

result_map = [id: id_1 val: {val_1, val_3}, id: id_2 var: {val_2}} ]

Код, который я пробовал:

var a = make(map[string]interface{})
for _, m := range data {
    for _, n := range data {
        if m["id"] == n["id"] {
            for l, k := range n {
                c[l] = k
            }
        }
    }
}

Есть ли способ, которым это можно сделать? Использую Голанг 1.7

Спасибо

1 Ответ

0 голосов
/ 14 мая 2018

Простое слияние

Да, их можно объединить, но, поскольку в карте результатов может быть несколько значений, связанных с одним и тем же ключом, типом значения должен быть фрагмент, например map[string][]string.

Чтобы выполнить слияние, просто расположите карты для слияния и добавьте каждое значение из исходных карт к срезу, связанному с тем же ключом в карте результатов.

Одна вещь, на которую нужно обратить внимание, это то, что, как только вы выполните добавление, вы должны назначить обратно результирующий срез тому же ключу на карте результатов.

Это простая реализация:

func merge(ms ...map[string]string) map[string][]string {
    res := map[string][]string{}
    for _, m := range ms {
        for k, v := range m {
            res[k] = append(res[k], v)
        }
    }
    return res
}

Эта merge() функция имеет переменный параметр, что означает, что вы можете передать ей любое количество карт.

Обратите внимание, что вам не нужно инициализировать фрагменты на целевой карте, так как индексирование карты с ключом, которого еще нет в нем, приведет к нулевому значению ее типа (которое nil для срезов), и вы можете добавить к срезу nil, встроенная функция append() заботится о (пере) распределении.

Тестирование:

m1 := map[string]string{"id_1": "val_1"}
m2 := map[string]string{"id_2": "val_2"}
m3 := map[string]string{"id_1": "val_3"}

res := merge(m1, m2, m3)
fmt.Println(res)

Вывод (попробуйте на Go Playground ):

map[id_1:[val_1 val_3] id_2:[val_2]]

Как избежать дубликатов

Обратите внимание, что вышеприведенный merge() не будет отфильтровывать дубликаты, то есть, если одна и та же пара "id_1": "val_1" содержится в нескольких входных картах, она будет многократно перечисляться в цели, как "id_1": ["val_1", "val_1", "val_x"]. Чтобы отфильтровать такие дубликаты (чтобы перечислить их только один раз в целевом объекте), мы должны проверить это перед выполнением добавления (и, если мы столкнулись с этим ранее, пропустить добавление).

Вот как это можно сделать:

func merge(ms ...map[string]string) map[string][]string {
    res := map[string][]string{}
    for _, m := range ms {
    srcMap:
        for k, v := range m {
            // Check if (k,v) was added before:
            for _, v2 := range res[k] {
                if v == v2 {
                    continue srcMap
                }
            }
            res[k] = append(res[k], v)
        }
    }
    return res
}

Тестирование:

m1 := map[string]string{"id_1": "val_1"}
m2 := map[string]string{"id_2": "val_2", "id_1": "val_1"}
m3 := map[string]string{"id_1": "val_3"}

res := merge(m1, m2, m3)
fmt.Println(res)

Вывод (попробуйте на Go Playground ):

map[id_1:[val_1 val_3] id_2:[val_2]]

Мы видим, что "id_1": "val_1" был включен как в m1, так и m2, но значение "val_1" указано только один раз в срезе, связанном с ключом "id_1" на целевой карте.

...