英文:
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."
}
}
}
我尝试过的是:
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."
}
}
在循环中,只会得到该类别的最后一个元素。我不明白如何在不使用任何静态值的情况下获取数组中的所有元素。
我已经花了几个小时在这个问题上。有人能告诉我错在哪里吗?
英文:
I am trying to create an array from already created array. Array that I have is
{
"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."
}
Now I need to create an array and populate data like:
"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."
}
}
}
What I have tried is:
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
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
arr := make(map[string]interface{})
arrCate := make(map[string]interface{})
for _, data := range dataVals{
arrCate[data.Category] = data
}
arr["elements"] = arrCate
Then I get something like:
"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."
}
}
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
为了方便他人对我的解决方案进行批评,我在这里包含了代码,稍作修改:
package main
import (
"fmt"
"encoding/json"
"log"
"strings"
)
var dataAsString = `` //将数据放在 `` 之间
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() {
// 首先读取数据,我们使用解码器,因为输入是作为单独的 JSON 对象流而给出的,而不是一个大的单一对象。
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)
}
// 根据类别收集项目
catToItemSlice := CategoryToItemSliceMap{}
for _, v := range ourData {
catToItemSlice[v.Category] = append(catToItemSlice[v.Category], v)
}
// 将这些切片转换为 int -> Item 映射,以便我们获得编码 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
}
}
// 最简单的方法是获得 "elements: ",而不需要额外的外部 {} 大括号对
fmt.Printf("elements: ")
// 我们的输出中只有一个 JSON 对象,而且是一个映射,所以我们可以使用 Unmarshal,而不需要流编码器。并使用 MarshalIndent 获得漂亮的缩进。
out, err := json.MarshalIndent(catToIndexItemMap, "", " ")
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(out))
}
英文:
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:
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))
}
答案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)
英文:
// If atributes names equals , set value to fields
// target receive values of object
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))
}
}
}
}
// Use this exemple objects interfaces diffrents but fields are equals
// Assign(&target, &object)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论