检查地图是否是另一个地图的子集
Check if a map is subset of another map
这个问题已经用许多其他语言回答了。在带有简单地图(无嵌套)的 golang 中,如何确定一个地图是否是另一个地图的子集。例如:map[string]string{"a": "b", "e": "f"}
是 map[string]string{"a": "b", "c": "d", "e": "f"}
的子集。我想要一个通用方法。我的代码:
package main
import (
"fmt"
"reflect"
)
func main() {
a := map[string]string{"a": "b", "c": "d", "e": "f"}
b := map[string]string{"a": "b", "e": "f"}
c := IsMapSubset(a, b)
fmt.Println(c)
}
func IsMapSubset(mapSet interface{}, mapSubset interface{}) bool {
mapSetValue := reflect.ValueOf(mapSet)
mapSubsetValue := reflect.ValueOf(mapSubset)
if mapSetValue.Kind() != reflect.Map || mapSubsetValue.Kind() != reflect.Map {
return false
}
if reflect.TypeOf(mapSetValue) != reflect.TypeOf(mapSubsetValue) {
return false
}
if len(mapSubsetValue.MapKeys()) == 0 {
return true
}
iterMapSubset := mapSubsetValue.MapRange()
for iterMapSubset.Next() {
k := iterMapSubset.Key()
v := iterMapSubset.Value()
if value := mapSetValue.MapIndex(k); value == nil || v != value { // invalid: value == nil
return false
}
}
return true
}
当我想检查集合映射中是否存在子集映射键时,MapIndex
returns 类型值为零并且无法将其与任何内容进行比较。
毕竟我能把同样的工作做得更好吗?
Value.MapIndex()
returns a reflect.Value
是结构,nil
不是结构的有效值。您不能将结构值与 nil
.
进行比较
Value.MapIndex()
表示:
It returns the zero Value if key is not found in the map or if v represents a nil map.
所以判断键是否在映射中找不到,检查返回的 reflect.Value
是否是它的零值。为此,您可以使用 Value.IsValid()
方法。
您也不能(不应该)比较 reflect.Value
值。而是使用 Value.Interface()
获取它们的包装值,然后比较它们。
if v2 := mapSetValue.MapIndex(k); !v2.IsValid() || v.Interface() != v2.Interface() {
return false
}
正在测试:
a := map[string]string{"a": "b", "c": "d", "e": "f"}
b := map[string]string{"a": "b", "e": "f"}
fmt.Println(IsMapSubset(a, b))
c := map[string]string{"a": "b", "e": "X"}
fmt.Println(IsMapSubset(a, c))
输出将是(在 Go Playground 上尝试):
true
false
I want a generic method.
现在Go 1.18和泛型都来了,你可以写这样一个泛型函数;见下文,在此 Playground. Reflection, which is generally discouraged 中,不需要实现此功能。
package main
import "fmt"
func IsMapSubset[K, V comparable](m, sub map[K]V) bool {
if len(sub) > len(m) {
return false
}
for k, vsub := range sub {
if vm, found := m[k]; !found || vm != vsub {
return false
}
}
return true
}
type MyMap map[string]string
func main() {
a := map[string]string{"a": "b", "c": "d", "e": "f"}
b := map[string]string{"a": "b", "e": "f"}
c := map[string]string{"a": "b", "e": "g"}
fmt.Println(IsMapSubset(a, b))
fmt.Println(IsMapSubset(a, c))
fmt.Println(IsMapSubset(MyMap(a), c))
}
输出:
true
false
不过,
如果有人需要,这是可行的解决方案:
// IsMapSubset returns true if mapSubset is a subset of mapSet otherwise false
func IsMapSubset(mapSet interface{}, mapSubset interface{}) bool {
mapSetValue := reflect.ValueOf(mapSet)
mapSubsetValue := reflect.ValueOf(mapSubset)
if fmt.Sprintf("%T", mapSet) != fmt.Sprintf("%T", mapSubset) {
return false
}
if len(mapSetValue.MapKeys()) < len(mapSubsetValue.MapKeys()) {
return false
}
if len(mapSubsetValue.MapKeys()) == 0 {
return true
}
iterMapSubset := mapSubsetValue.MapRange()
for iterMapSubset.Next() {
k := iterMapSubset.Key()
v := iterMapSubset.Value()
value := mapSetValue.MapIndex(k)
if !value.IsValid() || v.Interface() != value.Interface() {
return false
}
}
return true
}
这个问题已经用许多其他语言回答了。在带有简单地图(无嵌套)的 golang 中,如何确定一个地图是否是另一个地图的子集。例如:map[string]string{"a": "b", "e": "f"}
是 map[string]string{"a": "b", "c": "d", "e": "f"}
的子集。我想要一个通用方法。我的代码:
package main
import (
"fmt"
"reflect"
)
func main() {
a := map[string]string{"a": "b", "c": "d", "e": "f"}
b := map[string]string{"a": "b", "e": "f"}
c := IsMapSubset(a, b)
fmt.Println(c)
}
func IsMapSubset(mapSet interface{}, mapSubset interface{}) bool {
mapSetValue := reflect.ValueOf(mapSet)
mapSubsetValue := reflect.ValueOf(mapSubset)
if mapSetValue.Kind() != reflect.Map || mapSubsetValue.Kind() != reflect.Map {
return false
}
if reflect.TypeOf(mapSetValue) != reflect.TypeOf(mapSubsetValue) {
return false
}
if len(mapSubsetValue.MapKeys()) == 0 {
return true
}
iterMapSubset := mapSubsetValue.MapRange()
for iterMapSubset.Next() {
k := iterMapSubset.Key()
v := iterMapSubset.Value()
if value := mapSetValue.MapIndex(k); value == nil || v != value { // invalid: value == nil
return false
}
}
return true
}
当我想检查集合映射中是否存在子集映射键时,MapIndex
returns 类型值为零并且无法将其与任何内容进行比较。
毕竟我能把同样的工作做得更好吗?
Value.MapIndex()
returns a reflect.Value
是结构,nil
不是结构的有效值。您不能将结构值与 nil
.
Value.MapIndex()
表示:
It returns the zero Value if key is not found in the map or if v represents a nil map.
所以判断键是否在映射中找不到,检查返回的 reflect.Value
是否是它的零值。为此,您可以使用 Value.IsValid()
方法。
您也不能(不应该)比较 reflect.Value
值。而是使用 Value.Interface()
获取它们的包装值,然后比较它们。
if v2 := mapSetValue.MapIndex(k); !v2.IsValid() || v.Interface() != v2.Interface() {
return false
}
正在测试:
a := map[string]string{"a": "b", "c": "d", "e": "f"}
b := map[string]string{"a": "b", "e": "f"}
fmt.Println(IsMapSubset(a, b))
c := map[string]string{"a": "b", "e": "X"}
fmt.Println(IsMapSubset(a, c))
输出将是(在 Go Playground 上尝试):
true
false
I want a generic method.
现在Go 1.18和泛型都来了,你可以写这样一个泛型函数;见下文,在此 Playground. Reflection, which is generally discouraged 中,不需要实现此功能。
package main
import "fmt"
func IsMapSubset[K, V comparable](m, sub map[K]V) bool {
if len(sub) > len(m) {
return false
}
for k, vsub := range sub {
if vm, found := m[k]; !found || vm != vsub {
return false
}
}
return true
}
type MyMap map[string]string
func main() {
a := map[string]string{"a": "b", "c": "d", "e": "f"}
b := map[string]string{"a": "b", "e": "f"}
c := map[string]string{"a": "b", "e": "g"}
fmt.Println(IsMapSubset(a, b))
fmt.Println(IsMapSubset(a, c))
fmt.Println(IsMapSubset(MyMap(a), c))
}
输出:
true
false
不过,
如果有人需要,这是可行的解决方案:
// IsMapSubset returns true if mapSubset is a subset of mapSet otherwise false
func IsMapSubset(mapSet interface{}, mapSubset interface{}) bool {
mapSetValue := reflect.ValueOf(mapSet)
mapSubsetValue := reflect.ValueOf(mapSubset)
if fmt.Sprintf("%T", mapSet) != fmt.Sprintf("%T", mapSubset) {
return false
}
if len(mapSetValue.MapKeys()) < len(mapSubsetValue.MapKeys()) {
return false
}
if len(mapSubsetValue.MapKeys()) == 0 {
return true
}
iterMapSubset := mapSubsetValue.MapRange()
for iterMapSubset.Next() {
k := iterMapSubset.Key()
v := iterMapSubset.Value()
value := mapSetValue.MapIndex(k)
if !value.IsValid() || v.Interface() != value.Interface() {
return false
}
}
return true
}