web-dev-qa-db-fra.com

Comment copier une carte?

J'essaie de copier le contenu d'une carte (amap) dans une autre (aSuperMap), puis d'effacer amap pour qu'il puisse prendre de nouvelles valeurs à la prochaine itération/boucle. Le problème est que vous ne pouvez pas effacer la carte sans effacer sa référence dans la super-carte également . Voici un pseudo code.

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)

}

J'ai aussi essayé des trucs dynamiques mais il y a évidemment une erreur (impossible d'affecter à zéro)

aSuperMap[y][x] = aData

La question est de savoir comment puis-je créer une carte associative? Dans PHP, j'utilise simplement aSuperMap [y] [x] = aData. Il semble que Golang n'a pas de méthode évidente. Si je supprime delete(aMap, x), sa référence à la super-carte est également supprimée. Si je ne le supprime pas, la super-carte se termine par des données en double. En gros, chaque boucle obtient aMap avec la nouvelle valeur et toutes les anciennes valeurs. 

45

Vous ne copiez pas la carte, mais la référence à la carte. Votre delete modifie donc les valeurs de votre carte d'origine et de la super carte. Pour copier une carte, vous devez utiliser une boucle for comme ceci:

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

Voici un exemple tiré de la documentation SO maintenant retirée:

// 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
}

Extrait de Maps - Copier une carte . L'auteur original était JepZ . Les détails de l'attribution sont disponibles sur la page contributor . La source est sous licence CC BY-SA 3.0 et se trouve dans l'archive Documentation . Sujet de référence ID: 732 et exemple ID: 9834.

76
Christian

J'utiliserais la récursion au cas où vous puissiez copier en profondeur la map et éviter les mauvaises surprises si vous changiez un élément map qui est lui-même une map.

Voici un exemple dans utils.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
}

Et son fichier de test (utils_test.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,
        },
    }

    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)
}

Il doit être assez facile à réadapter si vous avez besoin que la clé map soit autre chose que string.

3
Francesco Casula

Copie d’élément individuel, cela semble fonctionner pour moi avec un exemple simple. 

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)
1
GoGo

Vous devez copier manuellement chaque paire clé/valeur dans une nouvelle map. Il s’agit d’une boucle que les utilisateurs doivent reprogrammer à tout moment pour obtenir une copie complète d’un map.

Vous pouvez automatiquement générer cette fonction en installant mapper à partir de maps package à l'aide de

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

et courir

mapper -types string:aStruct

qui générera le fichier map_float_astruct.go contenant non seulement une (profonde) Copy pour votre carte, mais également d'autres fonctions map "manquantes" ContainsKey, ContainsValue, GetKeys et GetValues:

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
}

Divulgation complète: je suis le créateur de cet outil. Je l'ai créé et son package contenant parce que je me suis retrouvé à réécrire constamment ces algorithmes pour Go map pour différentes combinaisons de types.

0
Chris Redford