如何复制地图?

时间:2014-04-14 10:28:38

标签: go

我尝试将地图内容(amap)复制到另一个(aSuperMap)中,然后清除amap以便它可以在下一次迭代/循环。   问题是您无法清除超图中的地图without to clear its reference。  这是一些伪代码。

for something := range fruits{
        aMap := make(map[string]aStruct)
        aSuperMap := make(map[string]map[string]aStruct)

        for x := range something{
            aMap[x] = aData
            aSuperMap[y] = aMap
            delete(aMap, x)
    }
//save aSuperMap
  saveASuperMap(something)

}

我也试过一些动态的东西,但显然它会抛出一个错误(不能指定为零)

aSuperMap[y][x] = aData

问题是如何创建关联地图?在PHP中,我只使用aSuperMap [y] [x] = aData。似乎golang没有任何明显的方法。如果我删除delete(aMap, x),也会删除超级地图中的引用。如果我不删除它,则supermap最终会出现重复数据。基本上在每个循环上,它使用新值加上所有旧值获得aMap

6 个答案:

答案 0 :(得分:82)

您没有复制地图,而是复制地图。您的delete因此会修改原始地图和超级地图中的值。要复制地图,您必须使用for这样的循环:

for k,v := range originalMap {
  newMap[k] = v
}

以下是现已退役的SO文档中的一个示例:

// Create the original map
originalMap := make(map[string]int)
originalMap["one"] = 1
originalMap["two"] = 2

// Create the target map
targetMap := make(map[string]int)

// Copy from the original map to the target map
for key, value := range originalMap {
  targetMap[key] = value
}
  

摘自Maps - Copy a Map。原作者是JepZ。归因详情可在contributor page上找到。该来源在CC BY-SA 3.0下获得许可,可以在Documentation archive中找到。参考主题ID:732和示例ID:9834。

答案 1 :(得分:5)

我将使用递归,以防万一,以便您可以深度复制map并避免发生错误的情况,以防万一要更改本身为map的{​​{1}}元素。 / p>

以下是 utils.go 中的示例:

map

及其测试文件(即 utils_test.go ):

package utils

func CopyMap(m map[string]interface{}) map[string]interface{} {
    cp := make(map[string]interface{})
    for k, v := range m {
        vm, ok := v.(map[string]interface{})
        if ok {
            cp[k] = CopyMap(vm)
        } else {
            cp[k] = v
        }
    }

    return cp
}

如果您需要package utils import ( "testing" "github.com/stretchr/testify/require" ) func TestCopyMap(t *testing.T) { m1 := map[string]interface{}{ "a": "bbb", "b": map[string]interface{}{ "c": 123, }, } m2 := CopyMap(m1) m1["a"] = "zzz" delete(m1, "b") require.Equal(t, map[string]interface{}{"a": "zzz"}, m1) require.Equal(t, map[string]interface{}{ "a": "bbb", "b": map[string]interface{}{ "c": 123, }, }, m2) } 键而不是map来代替其他键,那么重新安装应该足够容易。

答案 2 :(得分:1)

单个元素副本,它似乎只是一个简单的例子。

maps := map[string]int {
    "alice":12,
    "jimmy":15,
}

maps2 := make(map[string]int)
for k2,v2 := range maps {
    maps2[k2] = v2
}

maps2["miki"]=rand.Intn(100)

fmt.Println("maps: ",maps," vs. ","maps2: ",maps2)

答案 3 :(得分:1)

您必须手动将每个键/值对复制到新的map。这是一个循环,人们在需要map的深拷贝时必须重新编程。

您可以通过使用{p> 3来安装maps软件包中的mapper来自动生成此功能。

go get -u github.com/drgrib/maps/cmd/mapper

并运行

mapper -types string:aStruct

将会生成文件map_float_astruct.go,该文件不仅包含地图的(深)Copy,还包含其他“缺失”的map函数ContainsKey,{{1} },ContainsValueGetKeys

GetValues

完全公开:我是该工具的创建者。我创建了它及其包含的包,因为我发现自己不断地为Go func ContainsKeyStringAStruct(m map[string]aStruct, k string) bool { _, ok := m[k] return ok } func ContainsValueStringAStruct(m map[string]aStruct, v aStruct) bool { for _, mValue := range m { if mValue == v { return true } } return false } func GetKeysStringAStruct(m map[string]aStruct) []string { keys := []string{} for k, _ := range m { keys = append(keys, k) } return keys } func GetValuesStringAStruct(m map[string]aStruct) []aStruct { values := []aStruct{} for _, v := range m { values = append(values, v) } return values } func CopyStringAStruct(m map[string]aStruct) map[string]aStruct { copyMap := map[string]aStruct{} for k, v := range m { copyMap[k] = v } return copyMap } 重写这些算法以适应不同的类型组合。

答案 4 :(得分:1)

seong's comment中所述:

另请参见http://golang.org/doc/effective_go.html#maps。重要的部分实际上是“对基础数据结构的引用”。这也适用于切片。

但是,这里的解决方案似乎都无法为适当的深层复制(也包括切片)提供解决方案。

我对Francesco Casula's answer做了一些改动,以适应地图和切片。


这应该包括复制地图本身以及复制任何子地图或切片。两者都受到相同的“基础数据结构”问题的影响。它还包括一个实用程序功能,可直接在片上执行相同类型的Deep Copy。

请记住,结果映射中的切片将为[]interface{}类型,因此在使用它们时,您将需要使用type assertion来检索期望类型的值。

用法示例

copy := CopyableMap(originalMap).DeepCopy()

源文件(util.go

package utils

type CopyableMap   map[string]interface{}
type CopyableSlice []interface{}

// DeepCopy will create a deep copy of this map. The depth of this
// copy is all inclusive. Both maps and slices will be considered when
// making the copy.
func (m CopyableMap) DeepCopy() map[string]interface{} {
    result := map[string]interface{}{}

    for k,v := range m {
        // Handle maps
        mapvalue,isMap := v.(map[string]interface{})
        if isMap {
            result[k] = CopyableMap(mapvalue).DeepCopy()
            continue
        }

        // Handle slices
        slicevalue,isSlice := v.([]interface{})
        if isSlice {
            result[k] = CopyableSlice(slicevalue).DeepCopy()
            continue
        }

        result[k] = v
    }

    return result
}

// DeepCopy will create a deep copy of this slice. The depth of this
// copy is all inclusive. Both maps and slices will be considered when
// making the copy.
func (s CopyableSlice) DeepCopy() []interface{} {
    result := []interface{}{}

    for _,v := range s {
        // Handle maps
        mapvalue,isMap := v.(map[string]interface{})
        if isMap {
            result = append(result, CopyableMap(mapvalue).DeepCopy())
            continue
        }

        // Handle slices
        slicevalue,isSlice := v.([]interface{})
        if isSlice {
            result = append(result, CopyableSlice(slicevalue).DeepCopy())
            continue
        }

        result = append(result, v)
    }

    return result
}

测试文件(util_tests.go

package utils

import (
    "testing"

    "github.com/stretchr/testify/require"
)

func TestCopyMap(t *testing.T) {
    m1 := map[string]interface{}{
        "a": "bbb",
        "b": map[string]interface{}{
            "c": 123,
        },
        "c": []interface{} {
            "d", "e", map[string]interface{} {
                "f": "g",
            },
        },
    }

    m2 := CopyableMap(m1).DeepCopy()

    m1["a"] = "zzz"
    delete(m1, "b")
    m1["c"].([]interface{})[1] = "x"
    m1["c"].([]interface{})[2].(map[string]interface{})["f"] = "h"

    require.Equal(t, map[string]interface{}{
        "a": "zzz", 
        "c": []interface{} {
            "d", "x", map[string]interface{} {
                "f": "h",
            },
        },
    }, m1)
    require.Equal(t, map[string]interface{}{
        "a": "bbb",
        "b": map[string]interface{}{
            "c": 123,
        },
        "c": []interface{} {
            "d", "e", map[string]interface{} {
                "f": "g",
            },
        },
    }, m2)
}

答案 5 :(得分:0)

您可以通过 encoding/gob 来回:

package main

import (
   "bytes"
   "encoding/gob"
)

func copyMap(in, out interface{}) {
   buf := new(bytes.Buffer)
   gob.NewEncoder(buf).Encode(in)
   gob.NewDecoder(buf).Decode(out)
}

func main() {
   a := map[string]int{"month": 12, "day": 31}
   b := make(map[string]int)
   copyMap(a, &b)
}

这也适用于其他软件包。下面是一个带有 net/url 的示例:

package main

import (
   "fmt"
   "net/url"
)

func copyVal(v url.Values) url.Values {
   u := url.URL{
      RawQuery: v.Encode(),
   }
   return u.Query()
}

func main() {
   a := url.Values{
      "west": {"left"}, "east": {"right"},
   }
   b := copyVal(a)
   fmt.Println(b)
}