Подтвердить что ты не робот

Как скопировать карту?

Я пытаюсь скопировать содержимое карты (amap) внутри другого (aSuperMap), а затем очистить amap, чтобы он мог принимать новые значения в следующем итерационном/цикле. Проблема в том, что вы не можете очистить карту не очищая ее ссылку в супермапе.  Вот несколько псевдокодов.

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), его ссылка с супер карты также будет удалена. Если я не удалю его, супермаш заканчивается дублирующимися данными. В основном на каждом цикле он получает amap с новым значением плюс все старые значения.

4b9b3361

Ответ 1

Вы копируете не карту, а ссылку на карту. Таким образом, ваше 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
}

Выдержка из карт - Скопировать карту. Первоначальный автор был JepZ. Детали атрибуции можно найти на странице участника. Источник лицензирован по CC BY-SA 3.0 и может быть найден в архиве документации. Идентификационный номер темы: 732 и пример ID: 9834.

Ответ 2

Я бы использовал рекурсию на всякий случай, чтобы вы могли глубоко копировать map и избежать неприятных сюрпризов на случай, если вы захотите изменить элемент map который является самой map.

Вот пример в 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
}

И его тестовый файл (т.е. 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)
}

Если вы хотите, чтобы ключ map был чем-то другим, а не string его было бы достаточно легко перенастроить.

Ответ 3

Индивидуальная копия экземпляра, похоже, работает для меня только с простым примером.

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)

Ответ 4

Вы должны вручную скопировать каждую пару ключ/значение на новую map. Это цикл, который люди должны перепрограммировать в любое время, когда им нужна глубокая копия map.

Вы можете автоматически сгенерировать функцию для этого, установив mapper из пакета maps, используя

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

и работает

mapper -types string:aStruct

который сгенерирует файл map_float_astruct.go содержащий не только (глубокую) Copy для вашей карты, но также и другие "отсутствующие" функции map ContainsKey, ContainsValue, GetKeys и 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
}

Полное раскрытие: я создатель этого инструмента. Я создал его и содержащий его пакет, потому что я постоянно переписывал эти алгоритмы для map Go для различных комбинаций типов.