-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi.go
293 lines (267 loc) · 7.59 KB
/
api.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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// Package seq provides helpers for “range-over-func” feature introduced in go 1.22.
package seq
import (
"iter"
"github.com/m4gshm/gollections/c"
"github.com/m4gshm/gollections/op"
)
// Of creates an iterator over the elements.
func Of[T any](elements ...T) iter.Seq[T] {
return func(yield func(T) bool) {
for _, v := range elements {
if ok := yield(v); !ok {
break
}
}
}
}
// ToSeq2 converts an iterator of single elements to an iterator of key/value pairs by applying the 'converter' function to each iterable element.
func ToSeq2[T, K, V any](seq iter.Seq[T], converter func(T) (K, V)) iter.Seq2[K, V] {
if seq == nil {
return func(_ func(K, V) bool) {}
}
return func(yield func(K, V) bool) {
seq(func(v T) bool {
return yield(converter(v))
})
}
}
// First returns the first element that satisfies the condition of the 'predicate' function.
func First[T any](seq iter.Seq[T], predicate func(T) bool) (v T, ok bool) {
if seq == nil {
return
}
seq(func(one T) bool {
if predicate(one) {
v = one
ok = true
return false
}
return true
})
return
}
// Firstt returns the first element that satisfies the condition of the 'predicate' function.
func Firstt[T any](seq iter.Seq[T], predicate func(T) (bool, error)) (v T, ok bool, err error) {
if seq == nil {
return v, false, nil
}
seq(func(one T) bool {
p, e := predicate(one)
if e != nil {
err = e
return false
} else if p {
v = one
ok = true
return false
}
return true
})
return v, ok, err
}
// Slice collects the elements of the 'seq' sequence into a new slice.
func Slice[T any](seq iter.Seq[T]) []T {
return SliceCap(seq, 0)
}
// SliceCap collects the elements of the 'seq' sequence into a new slice with predefined capacity.
func SliceCap[T any](seq iter.Seq[T], cap int) (out []T) {
if seq == nil {
return nil
}
if cap > 0 {
out = make([]T, 0, cap)
}
return Append(seq, out)
}
// Append collects the elements of the 'seq' sequence into the specified 'out' slice.
func Append[T any, TS ~[]T](seq iter.Seq[T], out TS) TS {
if seq == nil {
return nil
}
seq(func(v T) bool {
out = append(out, v)
return true
})
return out
}
// Reduce reduces the elements of the 'seq' sequence an one using the 'merge' function.
func Reduce[T any](seq iter.Seq[T], merge func(T, T) T) T {
result, _ := ReduceOK(seq, merge)
return result
}
// ReduceOK reduces the elements of the 'seq' sequence an one using the 'merge' function.
// Returns ok==false if the seq returns ok=false at the first call (no more elements).
func ReduceOK[T any](seq iter.Seq[T], merge func(T, T) T) (result T, ok bool) {
if seq == nil {
return result, false
}
started := false
seq(func(v T) bool {
if !started {
result = v
} else {
result = merge(result, v)
}
started = true
return true
})
return result, started
}
// Reducee reduces the elements of the 'seq' sequence an one using the 'merge' function.
func Reducee[T any](seq iter.Seq[T], merge func(T, T) (T, error)) (T, error) {
result, _, err := ReduceeOK(seq, merge)
return result, err
}
// ReduceeOK reduces the elements of the 'seq' sequence an one using the 'merge' function.
// Returns ok==false if the seq returns ok=false at the first call (no more elements).
func ReduceeOK[T any](seq iter.Seq[T], merge func(T, T) (T, error)) (result T, ok bool, err error) {
if seq == nil {
return result, false, nil
}
started := false
seq(func(v T) bool {
if !started {
result = v
} else {
result, err = merge(result, v)
if err != nil {
return false
}
}
started = true
return true
})
return result, started, err
}
// Accum accumulates a value by using the 'first' argument to initialize the accumulator and sequentially applying the 'merge' functon to the accumulator and each element of the 'seq' sequence.
func Accum[T any](first T, seq iter.Seq[T], merge func(T, T) T) T {
accumulator := first
if seq == nil {
return accumulator
}
seq(func(v T) bool {
accumulator = merge(accumulator, v)
return true
})
return accumulator
}
// Accumm accumulates a value by using the 'first' argument to initialize the accumulator and sequentially applying the 'merge' functon to the accumulator and each element of the 'seq' sequence.
func Accumm[T any](first T, seq iter.Seq[T], merge func(T, T) (T, error)) (accumulator T, err error) {
accumulator = first
if seq == nil {
return accumulator, nil
}
seq(func(v T) bool {
accumulator, err = merge(accumulator, v)
return err == nil
})
return accumulator, err
}
// Sum returns the sum of all elements.
func Sum[T c.Summable](seq iter.Seq[T]) (out T) {
return Accum(out, seq, op.Sum[T])
}
// HasAny finds the first element that satisfies the 'predicate' function condition and returns true if successful.
func HasAny[T any](seq iter.Seq[T], predicate func(T) bool) bool {
_, ok := First(seq, predicate)
return ok
}
// Contains finds the first element that equal to the example and returns true.
func Contains[T comparable](seq iter.Seq[T], example T) bool {
if seq == nil {
return false
}
contains := false
seq(func(v T) bool {
contains = v == example
return !contains
})
return contains
}
// Conv creates an iterator that applies the 'converter' function to each iterable element and returns value-error pairs.
// The error should be checked at every iteration step, like:
//
// var integers []int
// ...
// for s, err := range seq.Conv(integers, strconv.Itoa) {
// if err != nil {
// break
// }
// ...
// }
func Conv[From, To any](seq iter.Seq[From], converter func(From) (To, error)) iter.Seq2[To, error] {
return ToSeq2(seq, converter)
}
// Convert creates an iterator that applies the 'converter' function to each iterable element.
func Convert[From, To any](seq iter.Seq[From], converter func(From) To) iter.Seq[To] {
if seq == nil {
return func(_ func(To) bool) {}
}
return func(consumer func(To) bool) {
seq(func(from From) bool {
return consumer(converter(from))
})
}
}
// Flat is used to iterate over a two-dimensional sequence in single dimension form, like:
//
// var arrays iter.Seq[[]int]
// ...
// for e := range seq.Flat(arrays, as.Is) {
// ...
// }
func Flat[From, To any](seq iter.Seq[From], flattener func(From) []To) iter.Seq[To] {
if seq == nil {
return func(_ func(To) bool) {}
}
return func(yield func(To) bool) {
seq(func(v From) bool {
elementsTo := flattener(v)
for _, e := range elementsTo {
if !yield(e) {
return false
}
}
return true
})
}
}
// Filter creates an iterator that iterates only those elements for which the 'filter' function returns true.
func Filter[T any](seq iter.Seq[T], filter func(T) bool) iter.Seq[T] {
if seq == nil {
return func(_ func(T) bool) {}
}
return func(consumer func(T) bool) {
seq(func(e T) bool {
if filter(e) {
return consumer(e)
}
return true
})
}
}
// Filt creates an erroreable iterator that iterates only those elements for which the 'filter' function returns true.
func Filt[T any](seq iter.Seq[T], filter func(T) (bool, error)) iter.Seq2[T, error] {
if seq == nil {
return func(_ func(T, error) bool) {}
}
var err error
return func(yield func(T, error) bool) {
seq(func(e T) bool {
if err != nil {
return yield(e, err)
}
ok := false
ok, err = filter(e)
if ok {
return yield(e, nil)
}
return true
})
}
}
// KeyValue converts an iterator of single elements to a key/value pairs iterator by applying key, value extractors to each iterable element.
func KeyValue[T, K, V any](seq iter.Seq[T], keyExtractor func(T) K, valExtractor func(T) V) iter.Seq2[K, V] {
return ToSeq2(seq, func(t T) (K, V) { return keyExtractor(t), valExtractor(t) })
}