Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copying all elements of a map into another

Given

var dst, src map[K]V 

I can copy all entries from src into dst by doing

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

Is there a more idiomatic way to do this?

copy only works on slices (and string as a source).

like image 608
Mike Samuel Avatar asked Sep 15 '11 20:09

Mike Samuel


People also ask

How do you copy a map in go?

Maps in Go are reference types, so to deep copy the contents of a map, you cannot assign one instance to another. You can do this by creating a new, empty map and then iterating over the old map in a for range loop to assign the appropriate key-value pairs to the new map.


2 Answers

That looks like a perfectly fine way to do this to me. I don't think copying one map into another is common enough to have a one-liner solution.

like image 176
Lily Ballard Avatar answered Sep 25 '22 00:09

Lily Ballard


Using a simple for range loop is the most efficient solution.

Note that a builtin copy could not just copy the memory of src to the address of dst because they may have entirely different memory layout. Maps grow to accommodate the number of items stored in them. So for example if you have a map with a million elements, it occupies a lot more memory than a freshly created new map, and so a builtin copy could not just copy memory without allocating new.

If your map is big, you can speed up copying elements if you may create the destination map having a big-enough capacity to avoid rehashing and reallocation (the initial capacity does not bound its size), e.g.:

dst := make(map[K]V, len(src))  for k, v := range src {     dst[k] = v } 

If performance is not an issue (e.g. you're working with small maps), a general solution may be created using the reflect package:

func MapCopy(dst, src interface{}) {     dv, sv := reflect.ValueOf(dst), reflect.ValueOf(src)      for _, k := range sv.MapKeys() {         dv.SetMapIndex(k, sv.MapIndex(k))     } } 

This solution does not check if the arguments are really maps and if the destination is not nil. Testing it:

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) 

Output (try it on the Go Playground):

map[1:one 2:two] map[one:1 two:2] 
like image 23
icza Avatar answered Sep 25 '22 00:09

icza