-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslices_core.go
181 lines (146 loc) · 3.73 KB
/
slices_core.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
package generics
import (
"context"
"fmt"
"github.com/zeroflucs-given/generics/filtering"
)
// Concatenate all lists together
func Concatenate[T any](lists ...[]T) []T {
c := 0
for _, v := range lists {
c += len(v)
}
result := make([]T, 0, c)
for _, v := range lists {
result = append(result, v...)
}
return result
}
// Contains returns true if the set contains the specified value
func Contains[T comparable](items []T, value T) bool {
for _, v := range items {
if v == value {
return true
}
}
return false
}
// Cut removes the head of a list, returning it and the remainder of the list.
// If the input list is empty, cut returns the type-default.
func Cut[T any](items []T) (T, []T) {
var dflt T
if len(items) == 0 {
return dflt, nil
} else if len(items) == 1 {
return items[0], nil
}
return items[0], items[1:]
}
// DefaultIfEmpty checks to see if the specified slice is empty
// and if so, creates a slice with a specified default value.
func DefaultIfEmpty[T any](items []T, def T) []T {
if len(items) == 0 {
return []T{
def,
}
}
return items
}
// FirstIndexOf returns the first index of an item in the slice
func FirstIndexOf[T comparable](v T, items []T) int {
for i := 0; i < len(items); i++ {
if items[i] == v {
return i
}
}
return -1
}
// LastIndexOf returns the last index of an item in the slice
func LastIndexOf[T comparable](v T, items []T) int {
for i := len(items) - 1; i >= 0; i-- {
if items[i] == v {
return i
}
}
return -1
}
// Reverse creates a reversed copy of the slice
func Reverse[T any](items []T) []T {
output := make([]T, len(items))
for i, v := range items {
output[len(items)-i-1] = v
}
return output
}
// Skip the first N items of the slice.
func Skip[T any](items []T, n int) []T {
if len(items) <= n {
return nil
}
return items[n:]
}
// Take up to N items from the slice
func Take[T any](items []T, n int) []T {
if len(items) == 0 {
return nil
} else if len(items) < n {
return items[0:]
}
return items[0:n]
}
// TakeUntil takes items from the slice until the first item that passes the predicate.
func TakeUntil[T any](items []T, filters ...filtering.Expression[T]) []T {
filter := filtering.Not(filtering.And(filters...))
var result []T
for i, v := range items {
if !filter(i, v) {
break
}
result = append(result, v)
}
return result
}
// TakeUntilWithContext takes items from the slice until the first item that passes the predicate.
func TakeUntilWithContext[T any](ctx context.Context, items []T, filters ...filtering.ExpressionWithContext[T]) ([]T, error) {
filter := filtering.NotWithContext(filtering.AndWithContext(filters...))
var result []T
for i, v := range items {
match, err := filter(ctx, i, v)
if err != nil {
return nil, fmt.Errorf("error applying take filter to item %d: %w", i, err)
}
if !match {
break
}
result = append(result, v)
}
return result, nil
}
// TakeWhile takes items from the slice until the first item that fails the predicate.
func TakeWhile[T any](items []T, filters ...filtering.Expression[T]) []T {
filter := filtering.And(filters...)
var result []T
for i, v := range items {
if !filter(i, v) {
break
}
result = append(result, v)
}
return result
}
// TakeWhileWithContext takes items from the slice until the first item that fails the predicate.
func TakeWhileWithContext[T any](ctx context.Context, items []T, filters ...filtering.ExpressionWithContext[T]) ([]T, error) {
filter := filtering.AndWithContext(filters...)
var result []T
for i, v := range items {
match, err := filter(ctx, i, v)
if err != nil {
return nil, fmt.Errorf("error applying take filter to item %d: %w", i, err)
}
if !match {
break
}
result = append(result, v)
}
return result, nil
}