如何处理带分页的第三方API条件式JSON响应
问题描述
调用某第三方API,其返回JSON结构如下:
{ "data": [ { "id": 111, "highPriorityItems": [ { "time": "2022-01-01T00:00:50Z", "price": 5000.55 }, { "time": "2022-01-02T13:00:50Z", "price": 5600.55 } ], "lowPriorityItems": [ { "time": "2022-03-01T00:12:50Z", "price": 9000.55 }, { "time": "2022-03-02T22:00:50Z", "price": 6700.55 } ] } ] }
其中lowPriorityItems字段始终存在,highPriorityItems为可选字段,需优先保留该字段数据。
该API支持分页,同一id的lowPriorityItems和highPriorityItems可能分布在不同分页响应中。最终需要每个id对应一个合并两类数据切片的struct,后续可根据highPriorityItems是否为空选择使用对应数据。
现有Go代码框架如下,但不确定合并逻辑用遍历检查id还是map更高效:
package main type Payload struct { Data []Entity `json:"data"` } type Entity struct { Id string `json:"id"` HighPriorityItems []Item `json:"highPriorityItems"` LowPriorityItems []Item `json:"lowPriorityItems"` } type Item struct { time string price float64 } func main() { payloads := []&Payload{} for _, req := range requests { // 将响应反序列化为Payload结构体并追加到payloads切片 // payloads = append(payloads, payload) } // 此处需实现合并逻辑:合并相同id的Entity数据切片 }
解决方案
使用map实现高效合并是最优选择:遍历查找相同id的时间复杂度是O(n²),而map的键值对查找时间复杂度为O(1),在分页数据量较大时效率差距明显。
具体实现步骤
- 定义
map[string]*Entity作为合并容器,key为Entity的Id,value为指向合并后Entity的指针 - 遍历所有分页返回的
Payload,逐个处理其中的Entity:- 若map中无该id的Entity,初始化一个新Entity存入map(注意初始化切片避免nil)
- 若map中已有该id的Entity,将当前Entity的
HighPriorityItems和LowPriorityItems追加到已有Entity的对应切片中
- 最后将map中的值转换为切片,得到最终合并结果
修正后的完整代码
注意:原代码中Item的字段为小写,JSON反序列化会失败,需改为大写开头的导出字段:
package main import "encoding/json" type Payload struct { Data []Entity `json:"data"` } type Entity struct { Id string `json:"id"` HighPriorityItems []Item `json:"highPriorityItems"` LowPriorityItems []Item `json:"lowPriorityItems"` } type Item struct { Time string `json:"time"` Price float64 `json:"price"` } func main() { payloads := []*Payload{} // 假设requests是已定义的请求列表,此处省略请求及反序列化逻辑 // 初始化合并用的map entityMap := make(map[string]*Entity) for _, payload := range payloads { for _, entity := range payload.Data { // 复制当前entity的id,避免循环变量引用问题 id := entity.Id existingEntity, exists := entityMap[id] if !exists { // 初始化新的Entity,确保切片不为nil newEntity := Entity{ Id: id, HighPriorityItems: make([]Item, 0, len(entity.HighPriorityItems)), LowPriorityItems: make([]Item, 0, len(entity.LowPriorityItems)), } newEntity.HighPriorityItems = append(newEntity.HighPriorityItems, entity.HighPriorityItems...) newEntity.LowPriorityItems = append(newEntity.LowPriorityItems, entity.LowPriorityItems...) entityMap[id] = &newEntity } else { // 追加数据到已有Entity existingEntity.HighPriorityItems = append(existingEntity.HighPriorityItems, entity.HighPriorityItems...) existingEntity.LowPriorityItems = append(existingEntity.LowPriorityItems, entity.LowPriorityItems...) } } } // 将map转换为切片,方便后续使用 mergedEntities := make([]Entity, 0, len(entityMap)) for _, entity := range entityMap { mergedEntities = append(mergedEntities, *entity) } // 后续可根据mergedEntities处理业务逻辑 }
关键注意点
- 处理循环变量引用:在遍历
payload.Data时,需复制entity.Id,避免后续循环中变量被覆盖导致的错误 - 初始化切片:提前初始化切片并设置容量,可减少内存分配次数,提升性能
- 字段导出:Go中只有大写开头的字段才能被JSON包序列化/反序列化,必须修正
Item的字段名
内容的提问来源于stack exchange,提问作者Coldchain9
相关产品推荐
相关产品推荐

