forked from gookit/goutil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmap.go
83 lines (72 loc) · 1.65 KB
/
map.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package reflects
import (
"reflect"
"strconv"
)
// EachMap process any map data
func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) {
if fn == nil {
return
}
if mp.Kind() != reflect.Map {
panic("only allow map value data")
}
for _, key := range mp.MapKeys() {
fn(key, mp.MapIndex(key))
}
}
// EachStrAnyMap process any map data as string key and any value
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) {
EachMap(mp, func(key, val reflect.Value) {
fn(String(key), val.Interface())
})
}
// FlatFunc custom collect handle func
type FlatFunc func(path string, val reflect.Value)
// FlatMap process tree map to flat key-value map.
//
// Examples:
//
// {"top": {"sub": "value", "sub2": "value2"} }
// ->
// {"top.sub": "value", "top.sub2": "value2" }
func FlatMap(rv reflect.Value, fn FlatFunc) {
if fn == nil {
return
}
if rv.Kind() != reflect.Map {
panic("only allow flat map data")
}
flatMap(rv, fn, "")
}
func flatMap(rv reflect.Value, fn FlatFunc, parent string) {
for _, key := range rv.MapKeys() {
path := String(key)
if parent != "" {
path = parent + "." + path
}
fv := Indirect(rv.MapIndex(key))
switch fv.Kind() {
case reflect.Map:
flatMap(fv, fn, path)
case reflect.Array, reflect.Slice:
flatSlice(fv, fn, path)
default:
fn(path, fv)
}
}
}
func flatSlice(rv reflect.Value, fn FlatFunc, parent string) {
for i := 0; i < rv.Len(); i++ {
path := parent + "[" + strconv.Itoa(i) + "]"
fv := Indirect(rv.Index(i))
switch fv.Kind() {
case reflect.Map:
flatMap(fv, fn, path)
case reflect.Array, reflect.Slice:
flatSlice(fv, fn, path)
default:
fn(path, fv)
}
}
}