This repository has been archived by the owner on Aug 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
itertools.go
236 lines (220 loc) · 4.99 KB
/
itertools.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
package itertools
import (
"math"
"reflect"
"strings"
)
type Iterator chan interface{}
type Predicate func(interface{}) bool
type Number interface {
int | int8 | int32 | int64 | float32 | float64
}
// Iter returns an Iterator for the iterables parameter
func Iter[T any](iterables []T) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
for _, element := range iterables {
ch <- element
}
}()
return
}
// Next goes to the next item within an Iterator
func Next(ch Iterator) any {
return <-ch
}
// Repeat returns an Iterator which contains element parameter, size parameter amount of times
func Repeat(element any, size int) Iterator {
s := make([]any, size)
for i := range s {
s[i] = element
}
return Iter(s)
}
// Zip iterates over multiple data objects in sync
func Zip[T any](iterables ...[]T) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
if ok := ensureSameLength(iterables); !ok {
ch <- "all parameters must be of the same length"
return
}
var toSend []T
for index := range iterables[0] {
toSend = nil
for _, iterable := range iterables {
toSend = append(toSend, iterable[index])
}
ch <- toSend
}
}()
return
}
// Chain allows for multiple arrays of the same type to be iterated over
func Chain[T any](iterables ...[]T) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
for _, iterable := range iterables {
for index := range iterable {
ch <- iterable[index]
}
}
}()
return
}
// Count counts up from a certain number in an increment
func Count[T Number](start, step T) (ch Iterator) {
// consider changing step to uint
ch = make(Iterator)
go func() {
defer close(ch)
for {
ch <- start
start = start + step
}
}()
return
}
// Cycle goes over a string seemingly forever
func Cycle(iterable string) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
for {
letters := strings.SplitAfter(iterable, "")
for _, letter := range letters {
ch <- letter
}
}
}()
return
}
// Accumulate returns an Iterator that sends/receives accumulated sums, or accumulated results of other functions
func Accumulate(iterable []int, operator string, start int) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
if start != 0 {
ch <- start
}
toSend := iterable[0]
ch <- toSend + start
for _, element := range iterable[1:] {
switch operator {
case "add", "":
toSend = toSend + element
case "multiply":
toSend = toSend * element
case "power":
toSend = int(math.Pow(float64(toSend), float64(element)))
default:
ch <- "not valid operator"
return
}
ch <- toSend + start
}
}()
return
}
// Tee returns the next n number of items next to each other
func Tee[T []int | string](iterable T, n int) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
switch reflect.TypeOf(iterable).Kind() {
case reflect.String:
element := reflect.ValueOf(iterable).String()
for len(element) != 0 {
if len(element) < n {
ch <- element
return
}
ch <- element[0:n]
element = element[n:]
}
case reflect.Array, reflect.Slice:
element := reflect.ValueOf(iterable)
for element.Len() != 0 {
if element.Len() < n {
ch <- element
return
}
toSend := element.Slice(0, n)
element = element.Slice(n, element.Len())
ch <- toSend
}
}
}()
return
}
// Pairwise sends/receives two characters next in a string via an Iterator
func Pairwise(iterable string) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
innerCh := Tee(iterable, 2)
for element := range innerCh {
ch <- element
}
}()
return
}
// Dropwhile drops element from the iterable as long as the predicate is true - afterwards, returns every element using an Iterator
func Dropwhile[T Number](predicate Predicate, iterable []T) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
innerCh := Iter(iterable)
for element := range innerCh {
if !predicate(element) {
ch <- element
break
}
}
for element := range innerCh {
ch <- element
}
}()
return
}
func Filterfalse[T Number](predicate Predicate, iterable []T) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
innerCh := Iter(iterable)
for element := range innerCh {
if !predicate(element) {
ch <- element
}
}
}()
return
}
// ensureSameLength ensures that all nested arrays are the same length
func ensureSameLength[T any](nestedList [][]T) bool {
ch := Iter(nestedList)
first := Next(ch)
firstLength := reflect.ValueOf(first).Len()
for nested := range ch {
if reflect.ValueOf(nested).Len() != firstLength {
return false
}
}
return true
}
// Compress filters elements from data returning only those that have a corresponding element in selector that is true
func Compress[T any](data []T, selector []bool) (ch Iterator) {
ch = make(Iterator)
go func() {
defer close(ch)
for i, d := range data {
if len(selector) > i && selector[i] {
ch <- d
}
}
}()
return
}