Простое слияние
Да, их можно объединить, но, поскольку в карте результатов может быть несколько значений, связанных с одним и тем же ключом, типом значения должен быть фрагмент, например 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"
на целевой карте.