web-dev-qa-db-fra.com

Copie de tous les éléments d'une carte dans un 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
}

Existe-t-il une manière plus idiomatique de procéder?

copy ne fonctionne que sur les tranches (et string comme source).

62
Mike Samuel

Cela ressemble à une manière parfaitement fine de me faire ça. Je ne pense pas que copier une carte dans une autre soit assez courant pour avoir une solution à une ligne.

46
Lily Ballard

En utilisant un simple for range loop 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. Les cartes s'agrandissent pour accueillir le nombre d'éléments qu'elles contiennent. 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 nouveaux.

Si votre carte est grande, vous pouvez accélérer la copie des éléments si vous pouvez créer la carte de destination avec une capacité suffisamment grande pour éviter le ressassement et la réaffectation (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 à l'aide du package 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))
    }
}

Cette solution ne vérifie pas si les arguments sont vraiment des mappages et si la destination n'est pas nil. Le tester:

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-le sur le Go Playground ):

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

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
Ernestas Poskus