-
Notifications
You must be signed in to change notification settings - Fork 1
/
slice.go
175 lines (152 loc) · 3.83 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
package slice
import (
"math/rand"
"sort"
"github.com/kamstrup/fn/constraints"
)
// Mapping converts a slice from one type to another
func Mapping[S, T any](slice []S, f func(s S) T) []T {
if len(slice) == 0 {
return []T{}
}
result := make([]T, len(slice))
for i, s := range slice {
result[i] = f(s)
}
return result
}
// MappingIndex converts a slice from one type to another.
// The mapping function also receives the index of the element being transformed.
func MappingIndex[S, T any](slice []S, f func(i int, s S) T) []T {
if len(slice) == 0 {
return []T{}
}
result := make([]T, len(slice))
for i, s := range slice {
result[i] = f(i, s)
}
return result
}
// Gen builds a new slice of a given size.
// The generator function is called sz times.
//
// Example:
//
// tenRandomFloats := slice.Gen(10, rand.Float64)
func Gen[T any](sz int, generator func() T) []T {
result := make([]T, sz)
for i := range result {
result[i] = generator()
}
return result
}
// GenIndex builds a new slice of a given size.
// The generator function is called for each index in the new slice.
func GenIndex[T any](sz int, generator func(i int) T) []T {
result := make([]T, sz)
for i := range result {
result[i] = generator(i)
}
return result
}
// Copy returns a shallow copy of the given slice.
func Copy[T any](slice []T) []T {
if len(slice) == 0 {
return []T{}
}
cpy := make([]T, len(slice))
copy(cpy, slice)
return cpy
}
// Zero zeroes all elements in a slice.
func Zero[T any](slice []T) []T {
// compiles to runtime.memclr(), see https://github.com/golang/go/issues/5373
var zero T
for i := range slice {
slice[i] = zero
}
return slice
}
// SortAsc sorts a slice in-place.
// The argument is returned to facilitate easy chaining.
func SortAsc[T constraints.Ordered](slice []T) []T {
sort.Slice(slice, func(i, j int) bool {
return slice[i] < slice[j]
})
return slice
}
// SortDesc sorts a slice in-place.
// The argument is returned to facilitate easy chaining.
func SortDesc[T constraints.Ordered](slice []T) []T {
sort.Slice(slice, func(i, j int) bool {
return slice[i] > slice[j]
})
return slice
}
// Reverse reverses the elements of s in-place and returns s again for easy chaining.
func Reverse[T any](s []T) []T {
end := len(s) / 2
for i := 0; i < end; i++ {
swapIdx := len(s) - 1 - i
s[i], s[swapIdx] = s[swapIdx], s[i]
}
return s
}
// Shuffle pseudo-randomizes the elements in the slice in-place.
// Returns the slice again for easy chaining.
func Shuffle[T any](s []T) []T {
rand.Shuffle(len(s), func(i, j int) {
s[i], s[j] = s[j], s[i]
})
return s
}
// First returns the first element of s or the zero value of T
func First[T any](s []T) T {
if len(s) == 0 {
var zero T
return zero
}
return s[0]
}
// Last returns the last element of s or the zero value of T
func Last[T any](s []T) T {
if len(s) == 0 {
var zero T
return zero
}
return s[len(s)-1]
}
// Delete removes all slice entries where the predicate returns true.
// The input slice is changed in-place.
func Delete[T any](s []T, shouldDelete func(T) bool) []T {
// One pass deletion.
// We put entries to keep to the left, and entries to delete to the right,
// while preserving the ordering of the kept entries.
highestKeepIdx := 0
for idx := range s {
if !shouldDelete(s[idx]) {
if idx != highestKeepIdx {
s[highestKeepIdx], s[idx] = s[idx], s[highestKeepIdx]
}
highestKeepIdx++
}
}
// trim the columns
return s[:highestKeepIdx]
}
// Trim removes any zero-value entries from the beginning and end of a given slice.
// The input slice is unchanged and a sub-slice is returned.
func Trim[T comparable](s []T) []T {
if s == nil {
return nil
}
var (
zero T
start, end int
)
for start = 0; start < len(s) && s[start] == zero; start++ {
}
for end = len(s); end > start && s[end-1] == zero; end-- {
}
return s[start:end]
}