Copier tous les éléments d'une carte dans une autre

Donné

var dst, src map[K]V

, je peux copier toutes les entrées de src dans dst en faisant

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

Y a-t-il une façon plus idiomatique de le faire?

copy fonctionne uniquement sur les tranches (et string comme une source).

59
demandé sur Flimzy 2011-09-16 00:08:39

3 réponses

Cela ressemble à une excellente façon de me faire cela. Je ne pense pas que Copier une carte dans une autre soit assez commun pour avoir une solution à un seul revêtement.

45
répondu Kevin Ballard 2011-09-15 20:17:45

L'utilisation d'une simple boucle for range est la solution la plus efficace.

Notez qu'un copy intégré ne peut pas simplement copier la mémoire de src à l'adresse de dst car ils peuvent avoir une disposition de mémoire entièrement différente. Cartes de grandir pour accueillir le nombre d'éléments stockés. Ainsi, par exemple, si vous avez une carte avec un million d'éléments, elle occupe beaucoup plus de mémoire qu'une nouvelle carte fraîchement créée, et donc un copy intégré ne peut pas simplement copier de la mémoire sans allouer de nouvelle.

Si votre carte est grande, vous pouvez accélérer la copie des éléments si vous pouvez créer la carte de destination ayant une capacité suffisante pour éviter de ressasser et de réallouer (la capacité initiale ne limite pas sa taille), par exemple:

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

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

Si les performances ne sont pas un problème (par exemple, vous travaillez avec de petites cartes), une solution générale peut être créée en utilisant reflect Paquet:

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

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

Cette solution ne vérifie pas si les arguments sont vraiment des cartes et si la destination n'est pas nil. Test il:

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)

Sortie (essayez sur la Aller de l'aire de Jeux):

map[1:one 2:two]
map[one:1 two:2]
7
répondu icza 2016-11-10 11:23:30

Vous pouvez utiliser 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}
2
répondu Ernestas Poskus 2016-02-09 03:30:15