如何返回嵌套地图中键的值

huangapple go评论67阅读模式
英文:

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
}

huangapple
  • 本文由 发表于 2022年8月12日 19:46:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/73333661.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定