Копирование всех элементов карты в другую


дано

var dst, src map[K]V

Я могу скопировать все записи из src на dst делать

for k, v := range src {
    dst[k] = v
}

есть ли более идиоматические способ сделать это?

copy работает только на ломти (и string как источник).

3 59

3 ответа:

Это выглядит как совершенно прекрасный способ сделать это со мной. Я не думаю, что копирование одной карты в другую достаточно распространено, чтобы иметь однострочное решение.

использовать простой for range петля является наиболее эффективным решением.

обратите внимание, что встроенный copy не удалось просто скопировать память src в адрес dst потому что они могут иметь совершенно разные разметки памяти. Карты растут, чтобы вместить количество элементов, хранящихся в них. Так, например, если у вас есть карта с миллионом элементов, она занимает гораздо больше памяти, чем недавно созданная новая карта, и поэтому встроенная copy не удалось просто скопировать память без выделения новый.

если ваша карта большая, Вы можете ускорить копирование элементов, если вы можете создать карту назначения, имеющую достаточно большую емкость, чтобы избежать повторного хэширования и перераспределения (начальная емкость не ограничивает ее размер), например:

dst := make(map[K]V, len(src))

for k, v := range src {
    dst[k] = v
}

если производительность не является проблемой (например, вы работаете с маленькой карты), общее решение может быть создано с помощью reflect пакет:

func MapCopy(dst, src interface{}) {
    dv, sv := reflect.ValueOf(dst), reflect.ValueOf(src)

    for _, k := range sv.MapKeys() {
        dv.SetMapIndex(k, sv.MapIndex(k))
    }
}

это решение не проверяет, являются ли аргументы действительно карты и если пункт назначения не nil. Тестирование его:

m1 := map[int]string{1: "one", 2: "two"}
m2 := map[int]string{}
MapCopy(m2, m1)
fmt.Println(m2)

m3 := map[string]int{"one": 1, "two": 2}
m4 := map[string]int{}
MapCopy(m4, m3)
fmt.Println(m4)

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

map[1:one 2:two]
map[one:1 two:2]

вы могли бы использовать github.com/linkosmos/mapop

input :=  map[string]interface{}{
  "Key1": 2,
  "key3": nil,
  "val": 2,
  "val2": "str",
  "val3": 4,
}

input2 := map[string]interface{}{
  "a2": "str",
  "a3": 4,
}

input = mapop.Merge(input, input2)

input{"Key1": 2, "key3": nil, "val": 2, "val2": "str", "val3": 4, "a2": "str", "a3": 4}