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

huangapple go评论129阅读模式
英文:

How to dynamically assign objects to a string key in slices in Go?

问题

我正在尝试从已创建的数组中创建一个新的数组。我已经有的数组是:

{
"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."
}
}
}

我尝试过的是:

  1. arr := make(map[string]interface{})
  2. arrCate := make(map[string]interface{})
  3. arrCateFlower := make(map[int]interface{})
  4. arrCateColor := make(map[int]interface{})
  5. arrCateFruit := make(map[int]interface{})
  6. for index, data := range dataVals{
  7. if(data.Category == "flower"){
  8. arrCateFlower[index] = data
  9. }
  10. if(data.Category == "colors"){
  11. arrCateColor[index] = data
  12. }
  13. if(data.Category == "fruits"){
  14. arrCateFruit[index] = data
  15. }
  16. }
  17. arrCate["flowers"] = arrCateFlower
  18. arrCate["colors"] = arrCateColor
  19. arrCate["fruits"] = arrCateFruit
  20. arr["elements"] = arrCate

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

  1. arr := make(map[string]interface{})
  2. arrCate := make(map[string]interface{})
  3. for _, data := range dataVals{
  4. arrCate[data.Category] = data
  5. }
  6. 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."
}
}

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

我已经花了几个小时在这个问题上。有人能告诉我错在哪里吗?

英文:

I am trying to create an array from already created array. Array that I have is

  1. {
  2. "id": 1,
  3. "category": "fruits",
  4. "name": "Apple",
  5. "description": "Apple is my favorite fruit."
  6. }
  7. {
  8. "id": 2,
  9. "category": "colors",
  10. "name": "Red",
  11. "description": "Red color is always charming."
  12. }
  13. {
  14. "id": 3,
  15. "category": "flowers",
  16. "name": "Lotus",
  17. "description": "It is one of the most beautiful flowers in this world."
  18. }
  19. {
  20. "id": 4,
  21. "category": "colors",
  22. "name": "Pink",
  23. "description": "A romantic color, mostly liked by women."
  24. }
  25. {
  26. "id": 5,
  27. "category": "flowers",
  28. "name": "Rose",
  29. "description": "I love roses."
  30. }
  31. {
  32. "id": 6,
  33. "category": "fruits",
  34. "name": "Mango",
  35. "description": "Mango is one of my favorite fruits."
  36. }

Now I need to create an array and populate data like:

  1. "elements":{
  2. "fruits":{
  3. 0:{
  4. "id": 1,
  5. "category": "fruits",
  6. "name": "Apple",
  7. "description": "Apple is my favorite fruit."
  8. }
  9. 1:{
  10. "id": 6,
  11. "category": "fruits",
  12. "name": "Mango",
  13. "description": "Mango is one of my favorite fruits."
  14. }
  15. }
  16. "flowers":{
  17. 0:{
  18. "id": 3,
  19. "category": "flowers",
  20. "name": "Lotus",
  21. "description": "It is one of the most beautiful flowers in this world."
  22. }
  23. 1:{
  24. "id": 5,
  25. "category": "flowers",
  26. "name": "Rose",
  27. "description": "I love roses."
  28. }
  29. }
  30. "colors":{
  31. 0:{
  32. "id": 2,
  33. "category": "colors",
  34. "name": "Red",
  35. "description": "Red color is always charming."
  36. }
  37. 1:{
  38. "id": 4,
  39. "category": "colors",
  40. "name": "Pink",
  41. "description": "A romantic color, mostly liked by women."
  42. }
  43. }
  44. }

What I have tried is:

  1. arr := make(map[string]interface{})
  2. arrCate := make(map[string]interface{})
  3. arrCateFlower := make(map[int]interface{})
  4. arrCateColor := make(map[int]interface{})
  5. arrCateFruit := make(map[int]interface{})
  6. for index, data := range dataVals{
  7. if(data.Category == "flower"){
  8. arrCateFlower[index] = data
  9. }
  10. if(data.Category == "colors"){
  11. arrCateColor[index] = data
  12. }
  13. if(data.Category == "fruits"){
  14. arrCateFruit[index] = data
  15. }
  16. }
  17. arrCate["flowers"] = arrCateFlower
  18. arrCate["colors"] = arrCateColor
  19. arrCate["fruits"] = arrCateFruit
  20. arr["elements"] = arrCate

Where dataVals contain the unformatted data given at the top. By applying the above code I am able to get the proper output. But I don't think it is efficient way. If I try something like

  1. arr := make(map[string]interface{})
  2. arrCate := make(map[string]interface{})
  3. for _, data := range dataVals{
  4. arrCate[data.Category] = data
  5. }
  6. arr["elements"] = arrCate

Then I get something like:

  1. "elements":{
  2. "fruits":{
  3. "id": 6,
  4. "category": "fruits",
  5. "name": "Mango",
  6. "description": "Mango is one of my favorite fruits."
  7. }
  8. "flowers":{
  9. "id": 5,
  10. "category": "flowers",
  11. "name": "Rose",
  12. "description": "I love roses."
  13. }
  14. "colors":{
  15. "id": 4,
  16. "category": "colors",
  17. "name": "Pink",
  18. "description": "A romantic color, mostly liked by women."
  19. }
  20. }

the last elements of that particular category in the loop. I don't understand how can I get all the elements in the array without using any static values in code.

I have already spent hours in this. Can anyone please tell what am i missing in it?

答案1

得分: 9

我希望你能接受额外的外部 {} 对。没有外部 {} 对的版本请参考:https://play.golang.org/p/SSTgln0qJc

为了方便他人对我的解决方案进行批评,我在这里包含了代码,稍作修改:

  1. package main
  2. import (
  3. "fmt"
  4. "encoding/json"
  5. "log"
  6. "strings"
  7. )
  8. var dataAsString = `` //将数据放在 `` 之间
  9. type Item struct {
  10. Id int `json:"id"`
  11. Category string `json:"category"`
  12. Name string `json:"name"`
  13. Description string `json:"description"`
  14. }
  15. type CategoryToItemSliceMap map[string][]Item
  16. type CategoryToIndexItemMap map[string]map[int]Item
  17. func main() {
  18. // 首先读取数据,我们使用解码器,因为输入是作为单独的 JSON 对象流而给出的,而不是一个大的单一对象。
  19. decoder := json.NewDecoder(strings.NewReader(dataAsString))
  20. var ourData []Item
  21. for decoder.More() {
  22. var it Item
  23. err := decoder.Decode(&it)
  24. if err != nil {
  25. log.Fatalln(err)
  26. }
  27. ourData = append(ourData, it)
  28. }
  29. // 根据类别收集项目
  30. catToItemSlice := CategoryToItemSliceMap{}
  31. for _, v := range ourData {
  32. catToItemSlice[v.Category] = append(catToItemSlice[v.Category], v)
  33. }
  34. // 将这些切片转换为 int -> Item 映射,以便我们获得编码 JSON 中的索引号
  35. catToIndexItemMap := CategoryToIndexItemMap{}
  36. for k, v := range catToItemSlice {
  37. if catToIndexItemMap[k] == nil {
  38. catToIndexItemMap[k] = map[int]Item{}
  39. }
  40. for index, item := range v {
  41. catToIndexItemMap[k][index] = item
  42. }
  43. }
  44. // 最简单的方法是获得 "elements: ",而不需要额外的外部 {} 大括号对
  45. fmt.Printf("elements: ")
  46. // 我们的输出中只有一个 JSON 对象,而且是一个映射,所以我们可以使用 Unmarshal,而不需要流编码器。并使用 MarshalIndent 获得漂亮的缩进。
  47. out, err := json.MarshalIndent(catToIndexItemMap, "", " ")
  48. if err != nil {
  49. log.Fatalln(err)
  50. }
  51. fmt.Println(string(out))
  52. }
英文:

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

I hope you can live with the additional outer {} pair.

And without the outer {} pair: https://play.golang.org/p/SSTgln0qJc

To not just have a bunch of links and to enable easy criticism of my solution by others, I include the code here, slightly redacted:

  1. package main
  2. import (
  3. "fmt"
  4. "encoding/json"
  5. "log"
  6. "strings"
  7. )
  8. var dataAsString = `` //put data between the ``
  9. type Item struct {
  10. Id int `json:"id"`
  11. Category string `json:"category"`
  12. Name string `json:"name"`
  13. Description string `json:"description"`
  14. }
  15. type CategoryToItemSliceMap map[string][]Item
  16. type CategoryToIndexItemMap map[string]map[int]Item
  17. func main() {
  18. // first read the data, we use a decoder as the input was given
  19. // as a stream of seperate json objects and not a big single one.
  20. decoder := json.NewDecoder(strings.NewReader(dataAsString))
  21. var ourData []Item
  22. for decoder.More() {
  23. var it Item
  24. err := decoder.Decode(&it)
  25. if err != nil {
  26. log.Fatalln(err)
  27. }
  28. ourData = append(ourData, it)
  29. }
  30. // collect items according to categories
  31. catToItemSlice := CategoryToItemSliceMap{}
  32. for _,v := range ourData {
  33. catToItemSlice[v.Category] = append(catToItemSlice[v.Category],v)
  34. }
  35. // turn those slices into int -> Item maps so we get the index numbers
  36. // in the encoded json
  37. catToIndexItemMap := CategoryToIndexItemMap{}
  38. for k,v := range catToItemSlice {
  39. if catToIndexItemMap[k] == nil {
  40. catToIndexItemMap[k] = map[int]Item{}
  41. }
  42. for index, item := range v {
  43. catToIndexItemMap[k][index] = item
  44. }
  45. }
  46. // easiest way to get the "elements: " without an additional outer {}
  47. // brace pair
  48. fmt.Printf("elements: ")
  49. // We only have one json object in the output and that is a map, so we
  50. // can use Unmarshal and don't need a streaming encoder. And get nice
  51. // indentation with MarshalIndent.
  52. out, err := json.MarshalIndent(catToIndexItemMap, "", " ")
  53. if err != nil {
  54. log.Fatalln(err)
  55. }
  56. fmt.Println(string(out))
  57. }

答案2

得分: 0

// 如果属性名称相等,则将值设置为字段
// target接收对象的值
func Assign(target interface{}, object interface{}) {
t := reflect.ValueOf(target).Elem()
o := reflect.ValueOf(object).Elem()
for i := 0; i < o.NumField(); i++ {
for j := 0; j < t.NumField(); j++ {
if o.Type().Field(i).Name == t.Type().Field(j).Name {
t.Field(j).Set(o.Field(i))
}
}
}
}
// 使用此示例,对象接口不同但字段相等
// Assign(&target, &object)

英文:
  1. // If atributes names equals , set value to fields
  2. // target receive values of object
  3. func Assign(target interface{}, object interface{}) {
  4. t := reflect.ValueOf(target).Elem()
  5. o := reflect.ValueOf(object).Elem()
  6. for i := 0; i &lt; o.NumField(); i++ {
  7. for j := 0; j &lt; t.NumField(); j++ {
  8. if o.Type().Field(i).Name == t.Type().Field(j).Name {
  9. t.Field(j).Set(o.Field(i))
  10. }
  11. }
  12. }
  13. }
  14. // Use this exemple objects interfaces diffrents but fields are equals
  15. // Assign(&amp;target, &amp;object)

huangapple
  • 本文由 发表于 2017年6月1日 14:14:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/44299808.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定