forked from digisan/go-generics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslice.go
159 lines (135 loc) · 3.33 KB
/
slice.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
package gogenerics
import (
"fmt"
"strings"
)
func traverseSlice(slc []any, path string, sb *strings.Builder) {
for i, e := range slc {
if IsArrOrSlc(e) {
traverseSlice(e.([]any), fmt.Sprintf("%v.%d", path, i), sb)
} else {
// **
// with value
// **
// path := fmt.Sprintf("%v @ %v.%d", e, path, i)
// path = strings.Replace(path, "@ .", "@ ", 1)
// **
// without value
// **
path := fmt.Sprintf("%v.%d", path, i)
path = strings.TrimPrefix(path, ".")
sb.WriteString(path + "\n")
// debug
// if e != nil {
// fmt.Printf("%v @%p %s\n", slc[i], &slc[i], path)
// } else {
// fmt.Printf("%v %s\n", slc[i], path)
// }
}
}
}
func TraverseSlice(slc []any) []string {
var (
path = ""
sb = &strings.Builder{}
)
traverseSlice(slc, path, sb)
return strings.Split(strings.TrimSpace(sb.String()), "\n")
}
// paths are like '1.2.3', '4.6.2'
func CapacityForSlice(paths ...string) []int {
mLvlIndices := make(map[int][]int)
for _, path := range paths {
// fmt.Println(i, path)
for lvl, seg := range strings.Split(path, ".") {
if n, ok := AnyTryToType[int](seg); ok {
mLvlIndices[lvl] = append(mLvlIndices[lvl], n)
}
}
}
mLvlCap := make(map[int]int)
for lvl, indices := range mLvlIndices {
mLvlCap[lvl] = Max(indices...) + 1
}
_, values := MapToKVs(mLvlCap, func(ki int, kj int) bool { return ki < kj }, nil)
return values
}
func initSlice(slc *any, caps ...int) {
for lvl, c := range caps {
*slc = make([]any, c)
if lvl < len(caps)-1 {
for i := 0; i < c; i++ {
initSlice(&((*slc).([]any))[i], caps[1:]...)
}
} else if lvl == len(caps)-1 {
for i := 0; i < c; i++ {
((*slc).([]any))[i] = struct{}{}
}
}
break // keep 'break' here
}
}
// init multiple dimension slice
func InitSlice(caps ...int) []any {
var slc any = []any{}
initSlice(&slc, caps...)
return slc.([]any)
}
// slc must have enough dimension & capacity for all element,
// use 'InitSlice' to allocate multiple dimension slice before setting
func SetSlice(slc []any, value any, indicesDim ...any) (ok bool) {
if len(indicesDim) == 0 {
return false
}
for _, idxDim := range indicesDim {
if !IsUint(idxDim) {
return false
}
}
for i, idxDim := range indicesDim {
if idx, _ := AnyTryToType[int](idxDim); idx < len(slc) {
if i == len(indicesDim)-1 {
slc[idx] = value
return true
} else {
var ok bool
if slc, ok = slc[idx].([]any); !ok {
return false
}
}
} else {
return false
}
}
return true
}
// This can only set single value in nested slice, useless for further assignment
//
// func MakeSlice(value any, indicesDim ...any) (slc []any, err error) {
// if len(indicesDim) == 0 {
// return []any{value}, nil
// }
// for _, idxDim := range indicesDim {
// if !IsUint(idxDim) {
// return nil, fmt.Errorf("index path (indicesDim) must can be converted to unsigned int")
// }
// }
// for i, idxDim := range Reverse(indicesDim) {
// idx, _ := AnyTryToType[int](idxDim)
// if i == 0 { // value seg
// nNil := idx - len(slc)
// for i := 0; i < nNil; i++ {
// slc = append(slc, nil)
// }
// slc = append(slc, value)
// } else { // path seg
// slc = []any{slc}
// nNil := idx - len(slc)
// for i := 0; i <= nNil; i++ {
// slc = append(slc, []any{})
// }
// slc = Reverse(slc)
// }
// }
// return
// }