-
Notifications
You must be signed in to change notification settings - Fork 0
/
slice.go
152 lines (122 loc) · 4.31 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
package util
import (
"fmt"
"math"
"reflect"
)
// SlicePagerOpts pagination settings
// SlicePagerOpts 分页设置
type SlicePagerOpts struct {
// CurrentPage current page
// CurrentPage 当前页
CurrentPage int `json:"currentPage"`
// TotalPages total pages
// TotalPages 总页数
TotalPages int `json:"totalPages"`
// TotalNum total elements count of slice
// TotalNum 总共有多少条数据在slice
TotalNum int `json:"totalNum"`
// Limit how many slice elements per page
// Limit 每页将有多少条数据
Limit int `json:"limit"`
}
// SlicePager paginate slice by SlicePagerOpts
// SlicePager 基于slice做分页
func SlicePager(input interface{}, outut interface{}, p *SlicePagerOpts) (err error) {
page := p.CurrentPage
limit := p.Limit
inValue := reflect.ValueOf(input)
outValue := reflect.ValueOf(outut)
outType := reflect.TypeOf(outut)
if outType.Kind() != reflect.Ptr {
return fmt.Errorf("param outut is not a pointer")
}
t1 := inValue.Type()
t2 := outValue.Elem().Type()
if t1 != t2 {
return fmt.Errorf("input and output param type mismached, input type is %s, output type is %s", t1, t2)
}
offset := (page - 1) * limit
if offset < 0 {
offset = 0
}
end := offset + limit
if offset+limit > inValue.Len() {
end = inValue.Len()
}
start := offset
if offset > inValue.Len() {
start = inValue.Len()
}
data := inValue.Slice(start, end)
outValue.Elem().Set(data)
p.TotalNum = inValue.Len()
p.TotalPages = int(math.Ceil(float64(p.TotalNum) / float64(p.Limit)))
return nil
}
// DeleteByIndex delete slice element from slice by index
// Dont use this function on big slice
// Example see slice_test.go#TestDeleteByIndex()
// DeleteByIndex 以指定的索引下标删除slice中的某个元素,请勿用于巨大的slice
func DeleteByIndex(slice interface{}, index int) (err error) {
sliceType := reflect.TypeOf(slice)
if sliceType.Kind() != reflect.Ptr || sliceType.Elem().Kind() != reflect.Slice {
return fmt.Errorf("slice type is not a pointer slice")
}
sliceValue := reflect.ValueOf(slice)
result := sliceValue.Elem().Slice(0, index)
for i := index + 1; i < sliceValue.Elem().Len(); i++ {
result = reflect.Append(result, sliceValue.Elem().Index(i))
}
sliceValue.Elem().Set(result)
return
}
// DeleteByValue delete slice element from slice by value
// if value matched multiple elements, theese elements will be delete from slice
// Dont use this function on big slice
// Example see slice_test.go#TestDeleteByValue()
// DeleteByValue 以指定的值标删除slice中的N个元素,请勿用于巨大的slice
func DeleteByValue(slice interface{}, value interface{}) (err error) {
sliceType := reflect.TypeOf(slice)
if sliceType.Kind() != reflect.Ptr || sliceType.Elem().Kind() != reflect.Slice {
return fmt.Errorf("slice type is not a pointer slice")
}
valueType := reflect.TypeOf(value)
if sliceType.Elem().Elem().Kind() != valueType.Kind() {
return fmt.Errorf("slice elements type [%s] is not match value type [%s]", sliceType.Elem().Elem().Kind().String(), valueType.Kind().String())
}
valueValue := reflect.ValueOf(value)
sliceValue := reflect.ValueOf(slice)
result := reflect.MakeSlice(sliceType.Elem(), 0, 0)
for i := 0; i < sliceValue.Elem().Len(); i++ {
if !reflect.DeepEqual(sliceValue.Elem().Index(i).Interface(), valueValue.Interface()) {
result = reflect.Append(result, sliceValue.Elem().Index(i))
}
}
sliceValue.Elem().Set(result)
return nil
}
// InSlice check if element exists in a slice
// value type and slice element type must be same
// Dont use this function on big slice
// Example see slice_test.go#TestInSlice()
// InSlice 检测值是否存在于slice中
func InSlice(slice interface{}, value interface{}) (exists bool, err error) {
sliceType := reflect.TypeOf(slice)
if sliceType.Kind() != reflect.Slice {
return exists, fmt.Errorf("slice type is not a pointer slice")
}
valueType := reflect.TypeOf(value)
if sliceType.Elem().Kind() != valueType.Kind() {
return exists, fmt.Errorf("slice elements type [%s] is not match value type [%s]", sliceType.Elem().Elem().Kind().String(), valueType.Kind().String())
}
valueValue := reflect.ValueOf(value)
sliceValue := reflect.ValueOf(slice)
for i := 0; i < sliceValue.Len(); i++ {
if reflect.DeepEqual(sliceValue.Index(i).Interface(), valueValue.Interface()) {
exists = true
break
}
}
return
}