如何在golang中将对象动态分配给切片中的字符串键?

时间:2017-06-01 06:14:21

标签: arrays go slice

我正在尝试从已创建的数组创建一个数组。我拥有的数组是

{
  "id": 1,
  "category": "fruits",
  "name": "Apple",
  "description": "Apple is my favorite fruit."
}

{
  "id": 2,
  "category": "colors",
  "name": "Red",
  "description": "Red color is always charming."
}

{
  "id": 3,
  "category": "flowers",
  "name": "Lotus",
  "description": "It is one of the most beautiful flowers in this world."
}

{
  "id": 4,
  "category": "colors",
  "name": "Pink",
  "description": "A romantic color, mostly liked by women."
}
{
  "id": 5,
  "category": "flowers",
  "name": "Rose",
  "description": "I love roses."
}

{
  "id": 6,
  "category": "fruits",
  "name": "Mango",
  "description": "Mango is one of my favorite fruits."
}

现在我需要创建一个数组并填充数据:

"elements":{
   "fruits":{
      0:{
         "id": 1,
         "category": "fruits",
         "name": "Apple",
         "description": "Apple is my favorite fruit."
       }
     1:{
        "id": 6,
        "category": "fruits",
        "name": "Mango",
        "description": "Mango is one of my favorite fruits."
       }
     }
    "flowers":{
        0:{
            "id": 3,
            "category": "flowers",
            "name": "Lotus",
            "description": "It is one of the most beautiful flowers in this world."
         }
        1:{
          "id": 5,
          "category": "flowers",
          "name": "Rose",
          "description": "I love roses."
        }
      }
    "colors":{
       0:{
          "id": 2,
          "category": "colors",
          "name": "Red",
          "description": "Red color is always charming."
        }
      1:{
        "id": 4,
        "category": "colors",
        "name": "Pink",
        "description": "A romantic color, mostly liked by women."
       } 
    }
}

我试过的是:

    arr             := make(map[string]interface{})
    arrCate         := make(map[string]interface{})
    arrCateFlower   := make(map[int]interface{})
    arrCateColor    := make(map[int]interface{})
    arrCateFruit    := make(map[int]interface{})

    for index, data := range dataVals{
        if(data.Category == "flower"){
            arrCateFlower[index] = data
        }
        if(data.Category == "colors"){
            arrCateColor[index] = data  
        }
        if(data.Category == "fruits"){
            arrCateFruit[index] = data  
        }
    }
    arrCate["flowers"] = arrCateFlower
    arrCate["colors"] = arrCateColor
    arrCate["fruits"] = arrCateFruit
    arr["elements"] = arrCate

其中dataVals包含顶部给出的未格式化数据。通过应用上面的代码,我能够得到正确的输出。但我不认为这是有效的方式。如果我尝试像

那样的话
    arr             := make(map[string]interface{})
    arrCate         := make(map[string]interface{})

    for _, data := range dataVals{
      arrCate[data.Category] = data    
    }
    arr["elements"] = arrCate

然后我得到类似的东西:

"elements":{
   "fruits":{
              "id": 6,
              "category": "fruits",
              "name": "Mango",
              "description": "Mango is one of my favorite fruits."
            }
    "flowers":{
               "id": 5,
               "category": "flowers",
               "name": "Rose",
               "description": "I love roses."
              }
    "colors":{
               "id": 4,
               "category": "colors",
               "name": "Pink",
               "description": "A romantic color, mostly liked by women." 
             }
}

循环中该特定类别的最后一个元素。我不明白如何在不使用代码中的任何静态值的情况下获取数组中的所有元素。

我已经花了好几个小时。任何人都可以告诉我在里面缺少什么吗?

1 个答案:

答案 0 :(得分:7)

https://play.golang.org/p/y-I6Fb_61R

我希望您可以使用其他外{}对。

没有外{}对:https://play.golang.org/p/SSTgln0qJc

为了不只是拥有一堆链接并且容易被其他人批评我的解决方案,我在这里包含了代码,稍作修改:

package main

import (
    "fmt"
    "encoding/json"
    "log"
    "strings"
)

var dataAsString = `` //put data between the ``

type Item struct {
    Id          int    `json:"id"`
    Category    string `json:"category"`
    Name        string `json:"name"`
    Description string `json:"description"`
}

type CategoryToItemSliceMap map[string][]Item
type CategoryToIndexItemMap map[string]map[int]Item

func main() {
    // first read the data, we use a decoder as the input was given
    // as a stream of seperate json objects and not a big single one.

    decoder := json.NewDecoder(strings.NewReader(dataAsString))
    var ourData []Item
    for decoder.More() {
        var it Item
        err := decoder.Decode(&it)
        if err != nil {
            log.Fatalln(err)
        }
        ourData = append(ourData, it)
    }

    // collect items according to categories
    catToItemSlice := CategoryToItemSliceMap{}
    for _,v := range ourData {
        catToItemSlice[v.Category] = append(catToItemSlice[v.Category],v)
    }

    // turn those slices into int -> Item maps so we get the index numbers
    // in the encoded json
    catToIndexItemMap := CategoryToIndexItemMap{}
    for k,v := range catToItemSlice {
        if catToIndexItemMap[k] == nil {
            catToIndexItemMap[k] = map[int]Item{}
        }
        for index, item := range v {
           catToIndexItemMap[k][index] = item
        }
    }

    // easiest way to get the "elements: " without an additional outer {} 
    // brace pair
    fmt.Printf("elements: ")

    // We only have one json object in the output and that is a map, so we
    // can use Unmarshal and don't need a streaming encoder. And get nice
    // indentation with MarshalIndent.
    out, err := json.MarshalIndent(catToIndexItemMap, "", "    ")
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println(string(out))

}