При определении карты карт фрагментов карт с ошибкой «присвоение нулю», нужно ли заполнять или генерировать ключи на лету? - PullRequest
1 голос
/ 09 июля 2020

Я новичок в Go и использую его для некоторых манипуляций с данными

У меня есть программа python, которая принимает json ввод как dict of dicts of lists of dicts, как показано ниже:

{
    "64": {
        "-117": [{
            "lat": 64.1121952,
            "loc": "Northwest Territories",
            "lon": -117.3539847,
            "id": "GmtNT",
            "name": "Gameti"
        }],
        "-147": [{
            "lat": 64.838,
            "loc": "Alaska",
            "lon": -147.716,
            "id": "FairbanksAK",
            "name": "Fairbanks"
        },
        {
            "lat": 64.9,
            "loc": "Alaska",
            "lon": -147.4,
            "id": "IcFgObAK",
            "name": "Icefog Observatory"
        }]
    },
    "71": {
        "-125": [{
            "lat": 71.985123,
            "loc": "Northwest Territories",
            "lon": -125.2464831,
            "id": "SchshrbrNT",
            "name": "Sachs Harbour"
        }]
    }
}

Я пишу сценарий Go для генерации этого json для ввода. У меня уже есть рабочий go скрипт для получения данных в этом формате:

siteIDMap := make(map[string]map[string]string)

Пример вывода в терминале:

map[
 CydrvrNU: map[loc:Nunavut lat:70.476365 lng:-68.6012651 name:Clyde River]
 UkhktkNT: map[loc:Northwest Territories lat:70.7367504 lng:-117.7704441 name:Ulukhaktok]
 PrdhByAK: map[loc:Alaska lat:70.254704 lng:-148.3406 name:Prudhoe Bay]
 SchshrbrNT: map[loc:Northwest Territories lat:71.985123 lng:-125.2464831 name:Sachs Harbour]
]

Однако у меня возникли проблемы с последним шагом. Мне удалось попытаться инициализировать то, что, как я подозреваю, является правильным типом данных latLngMap := make(map[string]map[string][]map[string]string), и попытался заполнить его, но, очевидно, не могу без инициализации каждой отдельной комбинации широты и долготы!

Код, который у меня есть до сих пор для этого нужно:

//Already have 'siteIDMap' created in above code not shown

slice2 := []map[string]string{} //empty slice that can be added to

//Init map of Lat/Lng to site data
latLngMap := make(map[string]map[string][]map[string]string)

// for every site in map
for k, v := range siteIDMap {
    loc := v["loc"]
    lat := v["lat"]
    lng := v["lng"]
    name := v["name"]

    m := map[string]string{"id": k, "lat": lat, "lng": lng, "loc": loc, "name": name}

    latFloor := strings.Split(lat, ".")[0]
    lngFloor := strings.Split(lng, ".")[0]

    fmt.Println(m, latFloor, lngFloor)

    latLngMap[latFloor][lngFloor] = append(slice2, m)

}

Последняя строка дает ошибку panic: assignment to entry in nil map, что имеет смысл, поскольку значения широты и долготы еще не введены на карту как ключи

Но для чего-то столь громоздкого, как это, как его инициализировать?

Нужен ли мне map[-89 to +89] lat, и для каждого из этих map[-89 to +89] lng, и для каждого из них: []map[string]string{}

Если я это сделаю, вероятно, 90% этих комбинаций широты и долготы будут совершенно пустыми. Похоже на ужасную трату.

Как я могу создать эту структуру данных во время ее создания?

Я думал о создании структуры для этого большого вложенного типа данных, но я новичок в Go и не уверен, поможет ли / как это

1 Ответ

1 голос
/ 09 июля 2020

Вы можете инициализировать вложенные карты по мере необходимости - вам не нужно инициализировать весь диапазон возможных пар lat, lng.

Проблема в том, что make(map[string]map[string][]map[string]string) инициализирует карту string на map[string][]map[string]string, но не на карту string на []map[string]string. Таким образом, когда вы назначаете latLngMap[lat][lng], часть [lat] в порядке, но карты для части [lng] не инициализируются (это nil).

Таким образом, все, что вам нужно сделать, это инициализировать карты внутри latLngMap[lat], прежде чем что-либо в них положить. Вы можете сделать это в вашем for l oop по широтам.

//Already have 'siteIDMap' created in above code not shown

//Init map of Lat/Lng to site data
latLngMap := make(map[string]map[string][]map[string]string)

// for every site in map
for k, v := range siteIDMap {
    loc := v["loc"]
    lat := v["lat"]
    lng := v["lng"]
    name := v["name"]

    // initialize nested map for this lat if it was not already initialized 
    // by a previous iteration
    _, ok := latLngMap[lat]
    if !ok {
        latLngMap[lat] = make(map[string][]map[string]string)
        latLngMap[lat][lng] = make([]map[string]string, 1)
    }

    m := map[string]string{"id": k, "lat": lat, "lng": lng, "loc": loc, "name": name}

    latFloor := strings.Split(lat, ".")[0]
    lngFloor := strings.Split(lng, ".")[0]

    fmt.Println(m, latFloor, lngFloor)

    latLngMap[latFloor][lngFloor] = append(latLngMap[latFloor][lngFloor], m)
}

Обратите внимание, что я также изменил место создания срезов внутри вложенных карт. Это предотвратит появление ошибок, если два места имеют одинаковые lat, lng. Раньше, если их было два, первый заменялся вторым.

Вот упрощенная версия кода, работающего в Go Playground .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...