当前位置: 首页 > 面试题库 >

在Go中合并动态数据结构

赵俊远
2023-03-14
问题内容

我有传入的有效负载,无法更改。

{
"source": "some random source",
"table": "hosts_table",
"data": [
    ["address", "id", "services_with_info"],
    ["0.0.0.1", 1111, [
            ["service_3", "is very cool", 1],
            ["service_4", "is very cool", 2]
        ]
    ],
    ["0.0.0.2", 2222, [
            ["service_3", "is very cool", 3],
            ["service_4", "is very cool", 4]
        ]
    ]
]}

我需要获取“数据”的第一个索引并创建一个新的JSON对象,如下所示…

"data": [{
"address": "0.0.0.1", 
"id": 1111, 
"services_with_info":[
    {
        "service_name": "service_1", 
        "service_message": "is very cool", 
        "service_id": 1
    }, 
    {...}
]}, 
{...}]

然后[]Host从中构建一个,其数据结构的长度为5k个“主机”。我能够将其映射到结构,但需要首先将其转换为这种格式。我了解如何解组JSON,但前提是可以将有效负载转换为上述格式。


问题答案:

我不确定我是否了解您的需求。

可能是这样的事情?可能需要做一些工作,例如使指向结构的指针切片而不是结构的切片以防止分配和复制,错误处理,更多自定义逻辑来转换值,匿名化/封装转换中间使用的私有结构,向其中添加json标签这些结构等

我在IncomingPaylod上为Data字段创建了自定义的Unmarshaller:解析期望的数据,将其转换为[]
MyData并使用它更新Data字段。

我为Expected_data和Expected_services_with_info创建了自定义Unmarshallers,因为我们希望它作为值数组(3个值:字符串,整数和[字符串数组,整数(?),整数]),但是我想将其转换为漂亮的结构。如果您不喜欢它,可以将其删除,将所需的数据解组到[]
interface {},并像[] interface {} {string,int,[] interface {}
{string,int,int}}一样使用它。容易出错,因此我更喜欢结构,它更易于阅读,维护和重构(我认为您的应用程序中包含更多字段)。

https://play.golang.org/p/xHTvyhecra

package main

import (
    "encoding/json"
    "fmt"
    "strconv"
)

type IncomingPayload struct {
    Source string      `json:"source"`
    Table  string      `json:"table"`
    Data   MyDataSlice `json:"data"`
}
type MyDataSlice []MyData

type MyData struct {
    Address            string              `json:"address"`
    ID                 string              `json:"id"`
    Services_with_info []MyServiceWithInfo `json:"services_with_info"`
}

type MyServiceWithInfo struct {
    ServiceName    string `json:"service_name"`
    ServiceMessage string `json:"service_message"`
    ServiceID      int    `json:"service_id"`
}

type expected_data struct {
    IP   string
    ID   int
    Info []expected_services_with_info
}

type expected_services_with_info struct {
    Name string
    Desc string
    ID   int
}

func (ed *expected_data) UnmarshalJSON(buf []byte) error {
    tmp := []interface{}{&ed.IP, &ed.ID, &ed.Info}
    // converts ["address", "id", "services_with_info"] into a struct
    // will unmarshall "services_with_info" (ed.Info) with *expected_services_with_info.UnmarshalJSON
    json.Unmarshal(buf, &tmp)
    return nil
}

func (es *expected_services_with_info) UnmarshalJSON(buf []byte) error {
    tmp := []interface{}{&es.Name, &es.Desc, &es.ID}
    // converts ["service_3", "is very cool", 1] into a struct
    json.Unmarshal(buf, &tmp)
    return nil
}

func (md *MyDataSlice) UnmarshalJSON(p []byte) error {
    var incoming_data_slice []expected_data
    json.Unmarshal(p, &incoming_data_slice)
    //fmt.Println("incoming", incoming_data_slice)

    //transform incoming_data_slice to your needs using your data type
    for i := range incoming_data_slice {
        my_data := MyData{
            Address: incoming_data_slice[i].IP,               //copy
            ID:      strconv.Itoa(incoming_data_slice[i].ID), //some transformation
            //nil slice is totally fine, but if you wish you can do
            //Data: make(MyDataSlice, len(incoming_data_slice)),

        }

        //not sure what would be best: "i := range data" or "_, v := range data" (second one makes a copy? and causes allocation)
        for j := range incoming_data_slice[i].Info {
            tmp := MyServiceWithInfo{
                ServiceName: incoming_data_slice[i].Info[j].Name,
                ServiceMessage: incoming_data_slice[i].Info[j].Desc,
                ServiceID: incoming_data_slice[i].Info[j].ID,
            }
            my_data.Services_with_info = append(my_data.Services_with_info, tmp)
        }

        //and populate
        *md = append(*md, my_data)
    }

    return nil
}

func main() {

    test_json := `{
"source": "some random source",
"table": "hosts_table",
"data": [
    ["address", "id", "services_with_info"],
    ["0.0.0.1", 1111, [
            ["service_3", "is very cool", 1],
            ["service_4", "is very cool", 2]
        ]
    ],
    ["0.0.0.2", 2222, [
            ["service_3", "is very cool", 3],
            ["service_4", "is very cool", 4]
        ]
    ]
]}`

    var payload IncomingPayload
    json.Unmarshal([]byte(test_json), &payload)
    fmt.Println("payload", payload)

    buf, _ := json.MarshalIndent(payload, "", "\t")
    fmt.Println(string(buf))

}


 类似资料:
  • 问题内容: 我目前正在尝试在Go中实现Merkle- tree数据结构。基本上,我的最终目标是存储一小组结构化数据(最大10MB),并使该“数据库”可以轻松地与网络上分布的其他节点同步(请参阅参考资料)。由于没有类型检查,因此我已经在Node中有效地实现了这一点。这就是Go的问题,我想利用Go的编译时类型检查,尽管我也想拥有一个可以与任何提供的树一起使用的库。 简而言之,我想将结构用作merkle

  • 我有一个有许多记录的表。它有以下结构: 表(col1、col2、col3、col4、col5、col6): 还有很多很多其他的行。 因此,我想要一张桌子: 表(col1,col2,col3,col4_1,col4_2,col4_3,col5_1,col5_2,col5_3,col6_1,col6_2,col6_3): 换句话说:表中的某些部分具有相同的,但不同的。每个相同的行数在1-3之间变化(事

  • 问题内容: 假设我有一个数据帧字典: 我想将它们全部合并成这样: 我可以手动执行以下操作: 但是,有没有一种方法可以自动浏览字典并合并呢?任何帮助表示赞赏。 问题答案: 您可以直接传递dict并将属性访问到: 假设您只是想连接所有df,如果要合并,则需要解释什么是合并标准

  • 行动时刻-在FreeRADIUS中加入MySQL数据库 我们假设在尚未部署FreeRADIUS的系统上尚未安装MySQL。 我们将首先安装然后配置MySQL,以便它可用于FreeRADIUS。 安装MySQL 确保Linux服务器上安装了MySQL服务器。 下表可用作在本书中讨论的三种发行版中的每一种上安装MySQL的指南: 发行版 用于安装MySQL服务器的命令 CentOS yum insta

  • 如何根据后端返回的数据来进行动态合并渲染,合并的关键字段为jianyanneirong和jianyanneirong1,合并要求如下图(如果jianyanneirong和jianyanneirong1值不同则进行行合并,但是jianyanneirong1值为空的情况需要进行行列合并)

  • 我有三类,像故事,电影故事,照片 我想显示数据类别明智的数据从数据库 1.故事*data1*data2*data3 2.电影故事*data1*data2*data3 控制器: 型号: 查看: 数据库: 创建表home_page: 创建表(int(11)not NULLAUTO_INCREMENT,int(11)DEFAULT NULL,int(11)DEFAULT NULL,text,