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?
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