Dictionary 检查一个贴图是否是另一个贴图的子集

Dictionary 检查一个贴图是否是另一个贴图的子集,dictionary,go,generics,reflection,go-map,Dictionary,Go,Generics,Reflection,Go 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

这个问题已经用许多其他语言得到了回答。在具有简单映射(无嵌套)的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
返回类型的零值,使其无法与任何内容进行比较

毕竟,我能把同样的工作做得更好吗?

返回一个结构,而
nil
不是结构的有效值。无法将结构值与
nil
进行比较

Value.MapIndex()
声明:

如果在映射中找不到键或如果v表示nil映射,则返回零值

因此,要判断是否在地图中找不到该键,请检查返回的
reflect.Value
是否为其零值。为此,您可以使用该方法

您也不能(不应该)比较
reflect.Value
值。而是使用获取它们的包装值,并进行比较

if v2 := mapSetValue.MapIndex(k); v2.IsZero() || 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 1.18(将于2022年2月发布),该版本计划将泛型引入语言,那么您就可以编写这样一个泛型函数;见下文和本节。这样就没有必要诉诸反思

输出:

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
}
//如果mapSubset是mapSet的子集,则IsMapSubset返回true,否则返回false
func IsMapSubset(映射集接口{},映射子集接口{})bool{
mapSetValue:=reflect.ValueOf(映射集)
mapSubsetValue:=reflect.ValueOf(mapSubset)
如果fmt.Sprintf(“%T”,映射集)!=fmt.Sprintf(“%T”,映射子集){
返回错误
}
如果len(mapSetValue.MapKeys())
整洁的解决方案。我将在项目中添加一个TODO和您的答案链接,并等待go 1.18
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
}