向Golang中的嵌套映射[string]接口{}添加属性
我正在处理向Golang中的嵌套映射[string]接口{}添加属性,go,Go,我正在处理map[string]接口{}类型的数据。它可以在(map[string]interface{})类型中有无限数量的嵌套对象 编辑:此数据来自mongodb。我不能在这里真正应用golang的结构,因为每个文档的属性都不同。我所要做的就是获取嵌套最深的对象,向其添加一个新属性,并确保之后更新整个数据对象 这些数据来自远程API,我不知道其中的属性。我想添加的只是在最后一个对象中添加新属性(在本例中为“分数”),假设使用这个新属性(“物理”),数据将如下所示 data["person"]
map[string]接口{}
类型的数据。它可以在(map[string]interface{})类型中有无限数量的嵌套对象
编辑:此数据来自mongodb。我不能在这里真正应用golang的结构,因为每个文档的属性都不同。我所要做的就是获取嵌套最深的对象,向其添加一个新属性,并确保之后更新整个数据对象
这些数据来自远程API,我不知道其中的属性。我想添加的只是在最后一个对象中添加新属性(在本例中为“分数”),假设使用这个新属性(“物理”),数据将如下所示
data["person"] = map[string]interface{}{
"peter": map[string]interface{}{
"scores": map[string]interface{}{
"calculus": 88,
"algebra": 99,
"golang": 89,
"physics": 95,
},
},
}
我不确定如何将该属性添加到最后一个对象
我做了递归类型检查,能够得到每个字段并打印其值。但是,因为映射不是引用的,所以当我使用非复杂类型的值访问映射时,无法向原始映射添加值
package main
import "fmt"
func main() {
data := make(map[string]interface{})
data["person"] = map[string]interface{}{
"peter": map[string]interface{}{
"scores": map[string]interface{}{
"calculus": 88,
"algebra": 99,
"golang": 89,
},
},
}
parseMap(data)
}
func parseMap(aMap map[string]interface{}) interface{} {
var retVal interface{}
for _, val := range aMap {
switch val.(type) {
case map[string]interface{}:
retVal = parseMap(val.(map[string]interface{}))
//case []interface{}:
// retVal = parseArray(val.([]interface{}))
default:
//here i would have done aMap["physics"] = 95 if I could access the original map by reference, but that is not possible
retVal = aMap
}
}
return retVal
}
尽量避免使用原始
map[string]接口{}
类型。Goencoding/json
文件可以很好地处理字符串键控的映射,希望远程API能够为您处理的内容提供某种规范。(例如,您知道您希望在层次结构中的特定点上有一个person
顶级键和分数。)
我假设远程API是HTTP上的JSON。您可以将其结构建模为
type Input struct {
Person map[string]Person `json:"person"`
}
type Person struct {
Scores map[string]int `json:"scores"`
}
一旦json.Unmarshal()
ed数据到这个结构中,就可以直接设置
data.Person["peter"].Scores["physics"] = 95
然后再次执行json.Marshal()
结果。有一个完整的例子
如果您真的想直接操作map[string]接口{}
结构,我建议将每个“级别”拆分为单独的函数调用
func ParseTopLevel(data map[string]interface{}) {
switch peter := data["peter"].(type) {
case map[string]interface{}:
ParsePeter(peter)
}
}
map
类型不同,因此当您到达堆栈底部时,可以直接设置分数[“物理”]=95
。(在你的原始代码中,如果你不能像你建议的那样直接设置aMap[“physics”]
,我会感到惊讶,尽管设置的内容相当不精确;比较。)根据对这个问题的评论,目标是在嵌套最深的映射中设置一个值
使用以下函数查找最大嵌套级别的贴图。如果在最大嵌套级别有多个映射,此函数将返回这些映射中的任意一个
func findDeepest(m map[string]interface{}) (int, map[string]interface{}) {
depth := 0
candidate := m
for _, v := range m {
if v, ok := v.(map[string]interface{}); ok {
d, c := findDeepest(v)
if d+1 > depth {
depth = d + 1
candidate = c
}
}
}
return depth, candidate
}
如下所示,在深度嵌套贴图中设置值:
_, m := findDeepest(data)
m["physics"] = 95
.显示您迄今为止尝试的代码。描述查找“最后一个对象”的逻辑。它是字典键顺序中的最后一个对象,嵌套最深的对象还是其他什么?我添加了代码来描述查找“最后一个对象”的逻辑。从代码和文字中看,您的意图并不清楚。代码试图向包含非map[string]接口{}或[]接口{}的值的映射添加值。散文说将值添加到没有复杂值的映射中。好的,上面的代码只是检查每个属性的类型。我感兴趣的是在最后一个嵌套映射中添加一个新属性。如果你事先不知道你的属性名称,这似乎是不可能的。它是宽度优先、深度优先、嵌套最深还是????。密钥是如何排序的?我不能在这里真正应用结构,因为数据是mongo文档,我不知道它有什么属性。谢谢Cerise Limon!但是为什么需要深度变量?如果没有它,它似乎可以正常工作。深度变量用于选择任何子贴图中包含的最深贴图。样本数据不需要这个变量,因为每个级别最多有一个嵌套映射。好的,我明白了。谢谢想知道,当同一级别上有兄弟对象时会发生什么。@pro如果在最大嵌套级别上有多个映射,此函数将返回这些映射中的任意一个。
_, m := findDeepest(data)
m["physics"] = 95