Skip to content

Instantly share code, notes, and snippets.

@ChristopherThorpe
Created October 31, 2018 05:40
Show Gist options
  • Save ChristopherThorpe/fd3720efe2ba83c929bf4105719ee967 to your computer and use it in GitHub Desktop.
Save ChristopherThorpe/fd3720efe2ba83c929bf4105719ee967 to your computer and use it in GitHub Desktop.
Nested Map Lookup: find elements in golang maps of arbitrary depth
// NestedMapLookup implementation and usage example
// Run it at https://play.golang.org/p/VHRgMcLf0b1
//
// JSON is not required, but used to show the example in a "real" setting.
//
// This gist is copyright (c) 2018 Brightgate Inc.
// and licensed under the Creative Commons Attribution 4.0 International license
// https://creativecommons.org/licenses/by/4.0/legalcode
//
package main
import (
"fmt"
"encoding/json"
)
var deep = `{
"root": {
"internal": {
"int": 42,
"string": "string",
"float64": 6.022e23
}
}
}`
// NestedMapLookup
// m: a map from strings to other maps or values, of arbitrary depth
// ks: successive keys to reach an internal or leaf node (variadic)
// If an internal node is reached, will return the internal map
//
// Returns: (Exactly one of these will be nil)
// rval: the target node (if found)
// err: an error created by fmt.Errorf
//
func NestedMapLookup(m map[string]interface{}, ks ...string) (rval interface{}, err error) {
var ok bool
if len(ks) == 0 { // degenerate input
return nil, fmt.Errorf("NestedMapLookup needs at least one key")
}
if rval, ok = m[ks[0]]; !ok {
return nil, fmt.Errorf("key not found; remaining keys: %v", ks)
} else if len(ks) == 1 { // we've reached the final key
return rval, nil
} else if m, ok = rval.(map[string]interface{}); !ok {
return nil, fmt.Errorf("malformed structure at %#v", rval)
} else { // 1+ more keys
return NestedMapLookup(m, ks[1:]...)
}
}
func main() {
var m = make(map[string]interface{})
json.Unmarshal([]byte(deep), &m)
val, err := NestedMapLookup(m, "root", "internal", "float64")
fmt.Printf("(%T) %v\n", val, val)
val, err = NestedMapLookup(m, "root", "infernal")
fmt.Printf("%v\n", err)
}
// Expected output:
// (float64) 6.022e+23
// key not found; remaining keys: [infernal]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment