-
Notifications
You must be signed in to change notification settings - Fork 7
/
slice.go
201 lines (178 loc) · 4.81 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package utility
import (
"regexp"
"sort"
"strings"
)
// StringSliceContains determines if a string is in a slice.
func StringSliceContains(slice []string, item string) bool {
if len(slice) == 0 {
return false
}
for idx := range slice {
if slice[idx] == item {
return true
}
}
return false
}
// StringSliceIntersection returns the intersecting elements of slices a and b.
func StringSliceIntersection(a, b []string) []string {
inA := map[string]bool{}
var out []string
for _, elem := range a {
inA[elem] = true
}
for _, elem := range b {
if inA[elem] {
out = append(out, elem)
}
}
return out
}
// StringSliceSymmetricDifference returns only elements not in common between 2 slices
// (ie. inverse of the intersection).
func StringSliceSymmetricDifference(a, b []string) ([]string, []string) {
mapA := map[string]bool{}
mapAcopy := map[string]bool{}
for _, elem := range a {
mapA[elem] = true
mapAcopy[elem] = true
}
var inB []string
for _, elem := range b {
if mapAcopy[elem] { // need to delete from the copy in case B has duplicates of the same value in A
delete(mapA, elem)
} else {
inB = append(inB, elem)
}
}
var inA []string
for elem := range mapA {
inA = append(inA, elem)
}
return inA, inB
}
// UniqueStrings takes a slice of strings and returns a new slice with duplicates removed.
// Order is preserved.
func UniqueStrings(slice []string) []string {
seen := map[string]bool{}
var out []string
for _, s := range slice {
if seen[s] {
continue
}
seen[s] = true
out = append(out, s)
}
return out
}
// SplitCommas returns the slice of strings after splitting each string by
// commas.
func SplitCommas(originals []string) []string {
splitted := []string{}
for _, original := range originals {
splitted = append(splitted, strings.Split(original, ",")...)
}
return splitted
}
// GetSetDifference returns the elements in A that are not in B.
func GetSetDifference(a, b []string) []string {
setB := make(map[string]struct{})
setDifference := make(map[string]struct{})
for _, e := range b {
setB[e] = struct{}{}
}
for _, e := range a {
if _, ok := setB[e]; !ok {
setDifference[e] = struct{}{}
}
}
d := make([]string, 0, len(setDifference))
for k := range setDifference {
d = append(d, k)
}
return d
}
// IndexOf returns the first occurrence of a string in a sorted array.
func IndexOf(a []string, toFind string) int {
i := sort.Search(len(a), func(index int) bool {
return strings.Compare(a[index], toFind) >= 0
})
if i < 0 || i >= len(a) {
return -1
}
if a[i] == toFind {
return i
}
return -1
}
// StringMatchesAnyRegex determines if the string item matches any regex in
// the slice.
func StringMatchesAnyRegex(item string, regexps []string) bool {
for _, re := range regexps {
matched, err := regexp.MatchString(re, item)
if err == nil && matched {
return true
}
}
return false
}
// FilterSlice filters a slice of elements based on a filter function.
func FilterSlice[T any](slice []T, filterFunction func(T) bool) []T {
var filteredSlice []T
for _, item := range slice {
if filterFunction(item) {
filteredSlice = append(filteredSlice, item)
}
}
return filteredSlice
}
// ContainsOrderedSubsetWithComparator returns whether a slice
// contains an ordered subset using the given compare function.
func ContainsOrderedSubsetWithComparator[T any](superset, subset []T, compare func(T, T) bool) bool {
if len(superset) < len(subset) {
return false
}
var j int
for i := 0; i < len(superset) && j < len(subset); i++ {
if compare(superset[i], subset[j]) {
j++
}
}
return len(subset) == j
}
// ContainsOrderedSubset returns whether a slice
// contains an ordered subset using the equality
// operator.
func ContainsOrderedSubset[T comparable](superset, subset []T) bool {
return ContainsOrderedSubsetWithComparator(superset, subset, func(a, b T) bool {
return a == b
})
}
// StringSliceContainsOrderedPrefixSubset returns whether a slice
// contains an ordered subset of prefixes using strings.HasPrefix.
func StringSliceContainsOrderedPrefixSubset(superset, subset []string) bool {
return ContainsOrderedSubsetWithComparator(superset, subset, func(a, b string) bool {
return strings.HasPrefix(a, b)
})
}
// SliceBatches partitions the elems slice into batches with at most
// maxElemsPerBatch in each batch. If maxElemsPerBatch is not a positive
// integer, it will make batches of size 1.
func MakeSliceBatches[T any](elems []T, maxElemsPerBatch int) [][]T {
if len(elems) == 0 {
return nil
}
if maxElemsPerBatch <= 0 {
maxElemsPerBatch = 1
}
remainingElems := elems
var batches [][]T
for len(remainingElems) > maxElemsPerBatch {
batches = append(batches, remainingElems[0:maxElemsPerBatch:maxElemsPerBatch])
remainingElems = remainingElems[maxElemsPerBatch:]
}
batches = append(batches, remainingElems)
return batches
}