forked from gookit/goutil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmaputil.go
167 lines (148 loc) · 3.31 KB
/
maputil.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Package maputil provide map data util functions. eg: convert, sub-value get, simple merge
package maputil
import (
"reflect"
"strings"
"github.com/gookit/goutil/arrutil"
)
// Key, value sep char consts
const (
ValSepStr = ","
ValSepChar = ','
KeySepStr = "."
KeySepChar = '.'
)
// SimpleMerge simple merge two data map by string key. will merge the src to dst map
func SimpleMerge(src, dst map[string]any) map[string]any {
if len(src) == 0 {
return dst
}
if len(dst) == 0 {
return src
}
for key, val := range src {
if mp, ok := val.(map[string]any); ok {
if dmp, ok := dst[key].(map[string]any); ok {
dst[key] = SimpleMerge(mp, dmp)
continue
}
}
// simple merge
dst[key] = val
}
return dst
}
// Merge1level merge multi any map[string]any data. only merge one level data.
func Merge1level(mps ...map[string]any) map[string]any {
newMp := make(map[string]any)
for _, mp := range mps {
for k, v := range mp {
newMp[k] = v
}
}
return newMp
}
// func DeepMerge(src, dst map[string]any, deep int) map[string]any { TODO
// }
// MergeSMap simple merge two string map. merge src to dst map
func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string {
return MergeStringMap(src, dst, ignoreCase)
}
// MergeStringMap simple merge two string map. merge src to dst map
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string {
if len(src) == 0 {
return dst
}
if len(dst) == 0 {
return src
}
for k, v := range src {
if ignoreCase {
k = strings.ToLower(k)
}
dst[k] = v
}
return dst
}
// MergeMultiSMap quick merge multi string-map data.
func MergeMultiSMap(mps ...map[string]string) map[string]string {
newMp := make(map[string]string)
for _, mp := range mps {
for k, v := range mp {
newMp[k] = v
}
}
return newMp
}
// FilterSMap filter empty elem for the string map.
func FilterSMap(sm map[string]string) map[string]string {
for key, val := range sm {
if val == "" {
delete(sm, key)
}
}
return sm
}
// MakeByPath build new value by key names
//
// Example:
//
// "site.info"
// ->
// map[string]any {
// site: {info: val}
// }
//
// // case 2, last key is slice:
// "site.tags[1]"
// ->
// map[string]any {
// site: {tags: [val]}
// }
func MakeByPath(path string, val any) (mp map[string]any) {
return MakeByKeys(strings.Split(path, KeySepStr), val)
}
// MakeByKeys build new value by key names
//
// Example:
//
// // case 1:
// []string{"site", "info"}
// ->
// map[string]any {
// site: {info: val}
// }
//
// // case 2, last key is slice:
// []string{"site", "tags[1]"}
// ->
// map[string]any {
// site: {tags: [val]}
// }
func MakeByKeys(keys []string, val any) (mp map[string]any) {
size := len(keys)
// if last key contains slice index, make slice wrap the val
lastKey := keys[size-1]
if newK, idx, ok := parseArrKeyIndex(lastKey); ok {
// valTyp := reflect.TypeOf(val)
sliTyp := reflect.SliceOf(reflect.TypeOf(val))
sliVal := reflect.MakeSlice(sliTyp, idx+1, idx+1)
sliVal.Index(idx).Set(reflect.ValueOf(val))
// update val and last key
val = sliVal.Interface()
keys[size-1] = newK
}
if size == 1 {
return map[string]any{keys[0]: val}
}
// multi nodes
arrutil.Reverse(keys)
for _, p := range keys {
if mp == nil {
mp = map[string]any{p: val}
} else {
mp = map[string]any{p: mp}
}
}
return
}