英文:
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.Interface() {
return false
}
}
return true
}
当我想要检查子集映射的键是否存在于集合映射中时,MapIndex
返回类型的零值,使其无法与任何值进行比较。
总的来说,我能否更好地完成同样的工作?
英文:
This question is already answered in many other languages. In golang with simple maps (no nesting) how to find out if a map is subset of another. for example: map[string]string{"a": "b", "e": "f"}
is subset of map[string]string{"a": "b", "c": "d", "e": "f"}
. I want a generic method. My code:
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
}
When I want to check if subset map key exists in set map, MapIndex
returns zero value of type and make it impossible to compare it with anything.
Afterall can I do the same job better?
答案1
得分: 5
我想要一个通用的方法。
现在Go 1.18和泛型已经发布,你可以编写这样一个通用函数;请参考下面的代码和Playground中的示例。不需要使用反射来实现这个功能,反射通常是不鼓励使用的。
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
不过,关于NaN
的常规注意事项仍然适用。
英文:
> I want a generic method.
Now that Go 1.18 and generics are here, you can write such a generic function; see below and in this Playground. Reflection, which is generally discouraged, is not required to implement this functionality.
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))
}
Output:
true
false
The usual caveats about NaN
apply, though.
答案2
得分: 2
Value.MapIndex()
返回一个 reflect.Value
,它是一个结构体,而 nil
不是结构体的有效值。你不能将结构体值与 nil
进行比较。
Value.MapIndex()
的说明如下:
> 如果在映射中找不到键或者 v 表示一个空映射,则返回零值。
因此,要判断是否在映射中找不到键,可以检查返回的 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
英文:
Value.MapIndex()
returns a reflect.Value
which is a struct, and nil
is not a valid value for structs. You can't compare a struct value to nil
.
Value.MapIndex()
states that:
> It returns the zero Value if key is not found in the map or if v represents a nil map.
So to tell if the key was not found in the map, check if the returned reflect.Value
is its zero value. For that you may use the Value.IsValid()
method.
You also can't (shouldn't) compare reflect.Value
values. Instead obtain their wrapped value using Value.Interface()
, and compare those.
if v2 := mapSetValue.MapIndex(k); !v2.IsValid() || v.Interface() != v2.Interface() {
return false
}
Testing it:
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))
Output will be (try it on the Go Playground):
true
false
答案3
得分: 1
这是一个工作的解决方案,如果有人需要的话:
// IsMapSubset函数判断mapSubset是否是mapSet的子集,如果是则返回true,否则返回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
}
英文:
This is the working solution in case anyone needs:
// 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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论