在Go中合并动态数据结构 [英] Merge a dynamic data structure in Go

查看:225
本文介绍了在Go中合并动态数据结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个新来的有效载荷,我不能改变。

  {
source:一些随机源码,
table:hosts_table ,
data:[
[address,id,services_with_info],
[0.0.0.1,1111,[
[service_3 ,非常酷,1],
[service_4,非常酷,2]
]
],
[0.0.0.2,2222 ,[
[service_3,非常酷,3],
[service_4,非常酷,4]
]
]
]}

我需要获取data的第一个索引并创建一个新的JSON对象,看起来像这样...
$ b $ pre $ data:[{
address:0.0.0.1 ,
id:1111,
services_with_info:[
{
service_name:service_1,
service_message:非常酷 ,
service_id:1
},
{...}
]},
{...}]

,然后用它建立一个 [] Host 的数据st结构是5K主机长。我能够将其映射到一个结构,但需要首先将其转换为此格式。我了解如何解组JSON,但前提是我可以将有效负载转换为上述内容。

解决方案

我不确定我是否理解您的要求。



<可能是这样的一些事情?
可能需要一些工作,比如对结构指向一些指针,而不是一堆结构来防止分配和复制,错误处理,更多的定制逻辑来转换值,匿名化/封装转换过程中使用的私有结构,添加json标签到这些结构等。

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



我为expected_data和expected_services_with_info创建了自定义Unmarshallers,因为我们期望它作为值的数组(3个值:字符串,int和[数组字符串,int(?),int ]),但我想将它转换为漂亮的结构。如果你不喜欢它,你可以删除它,将预期数据解组为[] interface {},并使用它[] interface {} {string,int,[] interface {} {string,int,int}}。容易得到它错误,所以我更喜欢结构,更容易阅读和维护和重构(我认为你的应用程序中有更多的领域)。
$ b

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

  package main 

import(
encoding / json
fmt
strconv


类型IncomingPayload结构{
源字符串`json:源``
表字符串`json:table`
Data MyDataSlice`json: data`
}
类型MyDataSlice [] MyData

类型MyData结构{
地址字符串`json:地址``
ID字符串` json:id`
Services_with_info [] MyServiceWithInfo`json:services_with_info`
}

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

类型expected_data struct {
IP字符串
ID int
Info [] expected_services_with_info
}

类型expected_services_with_info结构{
名称字符串
描述字符串
ID int
}

func(ed * expected_data)UnmarshalJSON (buf [] byte)error {
tmp:= [] interface {} {& ed.IP,& ed.ID,& ed.Info}
//转换[address ,id,services_with_info]转换为struct
//将使用* expected_services_with_info解析services_with_info(ed.Info).UnmarshalJSON
json.Unmarshal(buf,& tmp)
返回nil
}

func(es * expected_services_with_info)UnmarshalJSON(buf [] byte)error {
tmp:= [] interface {} {& es.Name, & es.Desc,& es.ID}
//将[service_3,非常酷,1]转换为struct
json.Unmarshal(buf,& tmp)
返回零
}

func(md * MyDataSlice)Unm arshalJSON(p [] byte)错误{
var incoming_data_slice [] expected_data
json.Unmarshal(p,&incoming_data_slice)
//fmt.Println(\"incoming,incoming_data_slice)

//将incoming_data_slice转换为您的需要使用您的数据类型
for i:=范围incoming_data_slice {
my_data:= MyData {
Address:incoming_data_slice [i] .IP, //复制
ID:strconv.Itoa(incoming_data_slice [i] .ID),//一些转换
// nil slice完全没问题,但是如果你愿意,你可以做
//数据:make(MyDataSlice,len(incoming_data_slice)),

}

//不知道最好是什么:i:= range data或_,v :=范围数据(第二个副本?并导致分配)
for j:=范围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)
}

//并填充
* md = append(* md,my_data)
}

返回零

$ b func main(){

test_json:=`{
source:一些随机源码,
table:hosts_table,
data:[
[address,id,services_with_info],
[0.0.0.1,1111,[
[service_3,非常酷,1],
[service_4,非常酷,2]
]
],
[ 0.0.0.2,2222,[
[service_3,非常酷,3],
[service_4,非常酷,4]
]
]
]}`

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

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

}


I have this incoming payload, that I cannot change.

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

i need to take the first index of "data" and create a new JSON object, that looks like this...

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

and then build an []Host's from it the data structure is 5k "hosts" long. I was able to map this to a struct, but need to get it into this format first. I understand how to unmarshal the JSON, but only if I can convert the payload to the above.

解决方案

I'm not sure if I understood what you wants.

May be some thing like this? Probably it needs some work, like make slice of pointers to structs instead of slice of structs to prevent allocation and copy, error handling, more custom logic to convert values, anonymize/incapsulate private structs used in the middle of conversion, add json tags to those structures etc.

I create custom Unmarshaller for Data field on IncomingPaylod: parsing expected data, converting it to []MyData and updating Data field with it.

I created custom Unmarshallers for expected_data and expected_services_with_info because we expect it as array of values (3 values: string, int and [array of string, int(?), int]), but I want to convert it to nice structs. If you dont like it, you can delete it, Unmarshal expected data to []interface{} and work with it like []interface{}{string, int, []interface{}{string, int, int} }. Easy to get it wrong, so i like structs more, its easier to read and maintain and refactor (i think there are more fields in you app).

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中合并动态数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆