英文:
How to return value of a key in nested map
问题
我想编写一个通用函数func GetVal(map[interface{}]interface{}, key interface{}) interface{}
。它将接受一个map和一个要搜索的键,并返回值或nil。
该map可以具有任何数据类型,并且可以嵌套到任意级别。例如,
var s1 = "S1"
var s2 = "S2"
var s3 = s1 + "==" + s2 + "==S3"
var s4 = s3 + "==S4"
var nestedMap = map[interface{}]interface{}{
"data": map[interface{}]interface{}{
"TEST_KEY": "1234353453",
"metadata": map[interface{}]interface{}{
"created_time": "2022-08-06",
},
"custom_metadata": map[interface{}][]interface{}{
"destroyed": []interface{}{
&s1,
map[string]interface{}{
"auth": []interface{}{
"val3", "val4", "val45",
},
},
},
},
&s2: &[]*string{
&s1, &s2,
},
&s1: &[]int{
10, 20, 233,
},
123: &s3,
},
s3: []interface{}{
[]interface{}{
map[string]*string{
s4: &s4,
},
},
},
}
期望的返回值
GetVal(nestedMap, "metadata")
应返回{"created_time": "2022-08-06"}
GetVal(nestedMap, "destroyed")
应返回
{ &s1,
map[string]interface{}{
"auth": []interface{}{
"val3", "val4", "val45",
},
},
}
有没有办法在不使用外部库的情况下实现这个功能?
这个问题看起来类似于在Golang中访问类型为map[string]interface{}的嵌套map,但在我的情况下,字段不是有限的或总是相同的。
英文:
I want to write a generic function func GetVal(map[interface{}]interface{}, key interface{}) interface{}
. This will take a map and a key to search for and return either the value or nil.
The map can have any data type and can go to any level of nesting. For example,
var s1 = "S1"
var s2 = "S2"
var s3 = s1 + "==" + s2 + "==S3"
var s4 = s3 + "==S4"
var nestedMap = map[interface{}]interface{}{
"data": map[interface{}]interface{}{
"TEST_KEY": "1234353453",
"metadata": map[interface{}]interface{}{
"created_time": "2022-08-06",
},
"custom_metadata": map[interface{}][]interface{}{
"destroyed": []interface{}{
&s1,
map[string]interface{}{
"auth": []interface{}{
"val3", "val4", "val45",
},
},
},
},
&s2: &[]*string{
&s1, &s2,
},
&s1: &[]int{
10, 20, 233,
},
123: &s3,
},
s3: []interface{}{
[]interface{}{
map[string]*string{
s4: &s4,
},
},
},
}
Expected return values
GetVal(nestedMap, "metadata")
should return {"created_time": "2022-08-06"}
GetVal(nestedMap, "destroyed")
should return
{ &s1,
map[string]interface{}{
"auth": []interface{}{
"val3", "val4", "val45",
},
},
}
Is there a way to do it without an external library?
This question looks similar to
Accessing Nested Map of Type map[string]interface{} in Golang but in my case the fields are not limited or always same
答案1
得分: 2
问题有点晦涩,因为示例过于复杂。如果你想了解有关循环函数的知识,你应该从一些更简单的东西开始,比如:
var nestedMap = map[string]interface{}{
"k1": "v1",
"k2": map[string]interface{}{
"nestedK1": "nestedV1",
"nestedK2": "nestedV2",
"nestedK3": map[string]interface{}{
"superNestedK1": "FOUND!!!",
},
},
}
否则,解释会很困难。
然后你可以研究像这样的函数:
func GetVal(data map[string]interface{}, key string) (result interface{}, found bool) {
for k, v := range data {
if k == key {
return v, true
} else {
switch v.(type) {
case map[string]interface{}:
if result, found = GetVal(v.(map[string]interface{}), key); found {
return
}
}
}
}
return nil, false
}
之后,你可以考虑添加对 map[interface{}][]interface{}
这样花哨的东西的支持。
然而,如果你真的需要这样复杂的结构,我不确定整个应用程序的设计是否合适。
也许你还应该考虑在地图中搜索完整路径 k2.nestedK3.superNestedK1
。这将消除歧义。
英文:
The question is kind of cryptic because the example is overcomplicated. If you want to get knowledge regarding the recurrent functions, you should start with something simpler like:
var nestedMap = map[string]any{
"k1": "v1",
"k2": map[string]any{
"nestedK1": "nestedV1",
"nestedK2": "nestedV2",
"nestedK3": map[string]any{
"superNestedK1" : "FOUND!!!",
},
},}
Otherwise, an explanation will be hard.
Then you can work on functions like:
func GetVal(data map[string]any, key string) (result any, found bool) {
for k, v := range data {
if k == key {
return v, true
} else {
switch v.(type) {
case map[string]any:
if result, found = GetVal(v.(map[string]any), key); found {
return
}
}
}
}
return nil, false}
Later you can think about adding support for fancy stuff like map[interface{}][]interface{}
However, if you really need such complicated structure, I am not sure if the whole design of application is ok.
Maybe you should also think about adding searching for a full path inside the map k2.nestedK3.superNestedK1
. It will remove ambiguity.
答案2
得分: 0
// 支持通过路径获取值:例如 k2.nestedK3.superNestedK1
// 感谢Lukasz Szymik的答案,他的代码启发了我实现这个功能。
func GetValueByPathFromMap(data map[string]any, key string, passedKey string) (result any, found bool) {
keyAndPath := strings.SplitN(key, ".", 2)
currentKey := keyAndPath[0]
if passedKey != "" {
passedKey = passedKey + "." + currentKey
} else {
passedKey = currentKey
}
if _, isKeyExistInData := data[currentKey]; !isKeyExistInData {
logrus.Warnf("[W] key path { %s } not found", passedKey)
return
} else {
if len(keyAndPath) > 1 {
remainingPath := keyAndPath[1]
switch data[currentKey].(type) {
case map[string]any:
if result, found = GetValueByPathFromMap(data[currentKey].(map[string]any), remainingPath, passedKey); found {
return
}
}
} else {
return data[currentKey], true
}
}
return nil, false
}
英文:
// Supports getting value by path: i.e. k2.nestedK3.superNestedK1
// Thanks Lukasz Szymik for his answer, which inspired me to implement this functionality based on his code.
func GetValueByPathFromMap(data map[string]any, key string, passedKey string) (result any, found bool) {
keyAndPath := strings.SplitN(key, ".", 2)
currentKey := keyAndPath[0]
if passedKey != "" {
passedKey = passedKey + "." + currentKey
} else {
passedKey = currentKey
}
if _, isKeyExistInData := data[currentKey]; !isKeyExistInData {
logrus.Warnf("[W] key path { %s } not found", passedKey)
return
} else {
if len(keyAndPath) > 1 {
remainingPath := keyAndPath[1]
switch data[currentKey].(type) {
case map[string]any:
if result, found = GetValueByPathFromMap(data[currentKey].(map[string]any), remainingPath, passedKey); found {
return
}
}
} else {
return data[currentKey], true
}
}
return nil, false
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论