Repository navigation
Expand file tree
/
Copy pathitertools.go
More file actions
255 lines (206 loc) · 5.1 KB
/
Copy pathitertools.go
File metadata and controls
255 lines (206 loc) · 5.1 KB
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
// itertools.go is simply like python's itertools library
// to furnish many convenient and powerful tools to
// help us to develop more fast.
package goTools
import (
"fmt"
"golang.org/x/exp/constraints"
)
func factorial(n int) int {
var b int = 1
for n > 0 {
b *= n
n--
}
return b
}
// Combinations refer to python's `itertools.combinations`.
func Combinations[T any](conditions []T, r int) [][]T {
n := len(conditions)
if r > n {
return nil
}
indices := rangeFrom(0, r)
result := make([][]T, 0, factorial(n)/factorial(r))
result = append(result, toSlice(indices, conditions))
outer:
for {
var _tmp int
for _, i := range reverseArray(rangeFrom(0, r)) {
_tmp = i
if indices[i] != i+n-r {
break
}
if i == 0 {
break outer
}
}
indices[_tmp] += 1
for _, j := range rangeFrom(_tmp+1, r) {
indices[j] = indices[j-1] + 1
}
result = append(result, toSlice(indices, conditions))
}
return result
}
// Repeat refer to python's `itertools.Repeat`.
// Make an iterator that returns object over and over again.
// Runs indefinitely unless the times argument is greater than 0.
// Repeat(10, 3) --> 10 10 10
func Repeat[T any, R constraints.Integer](v T, times R) chan T {
ch := make(chan T)
switch {
case times > 0:
go func() {
defer close(ch)
for times > 0 {
times--
ch <- v
}
}()
default:
go func() {
defer close(ch)
for {
ch <- v
}
}()
}
return ch
}
// Count refer to python's `itertools.Count`.
// Make an iterator that returns evenly spaced values starting with number start.
// Count(10) --> 10 11 12 13 14 ...
// Count(2.5, 0.5) --> 2.5 3.0 3.5 ...
func Count[T constraints.Integer | constraints.Float](start T, times T) chan T {
ch := make(chan T)
go func() {
defer close(ch)
for {
ch <- start
start += times
}
}()
return ch
}
// Operate 策略模式
type Operate[T constraints.Float | constraints.Integer] interface {
// execute is used to implement various operator protocol.
execute(total, element T) T
}
// Add +
type Add[T constraints.Float | constraints.Integer] struct {
}
func (Add[T]) execute(total, element T) T {
return total + element
}
// Sub -
type Sub[T constraints.Float | constraints.Integer] struct {
}
func (Sub[T]) execute(total, element T) T {
return total - element
}
// Mul *
type Mul[T constraints.Float | constraints.Integer] struct {
}
func (Mul[T]) execute(total, element T) T {
return total * element
}
// Div /
type Div[T constraints.Float | constraints.Integer] struct {
}
func (Div[T]) execute(total, element T) T {
return total / element
}
// Accumulate refer to python's `itertools.Accumulate`.
// Make an iterator that returns accumulated sums,
// or accumulated results of other binary functions (specified via the optional func argument).
// By now it only supports four kind of operators.
func Accumulate[T constraints.Float | constraints.Integer](iter []T, operator string, initial T) []T {
var operatorFunc Operate[T]
switch operator {
case "-":
operatorFunc = Sub[T]{}
case "/":
operatorFunc = Div[T]{}
case "*":
operatorFunc = Mul[T]{}
case "+":
operatorFunc = Add[T]{}
default:
err := fmt.Errorf("invalid operator: %s", operator)
fmt.Println(err.Error())
return nil
}
total := initial
result := make([]T, 0, len(iter)+1)
result = append(result, total)
for _, element := range iter {
total = operatorFunc.execute(total, element)
result = append(result, total)
}
return result
}
// Pairwise refer to python's `itertools.Pairwise`.
// Return successive overlapping pairs taken from the input iterable.
func Pairwise[T constraints.Ordered](iter []T) [][]T {
result := make([][]T, 0, len(iter))
for i, j := 0, 1; j < len(iter); i, j = i+1, j+1 {
result = append(result, []T{iter[i], iter[j]})
}
return result
}
// Chain refer to python's `itertools.Chain`.
// Make an iterator that returns elements from the first iterable until it is exhausted,
// then proceeds to the next iterable, until all of the iterables are exhausted.
// Used for treating consecutive sequences as a single sequence.
func Chain[T constraints.Ordered](iter ...[]T) []T {
if len(iter) == 1 {
return iter[0]
}
if len(iter) == 0 {
return []T{}
}
capacity := 0
for _, item := range iter {
capacity += len(item)
}
result := make([]T, 0, capacity)
for _, item := range iter {
result = append(result, item...)
}
return result
}
// toSlice should support more output form. TODO:
func toSlice[T any](idx []int, array []T) []T {
combineArray := make([]T, 0, len(array))
for _, i := range idx {
combineArray = append(combineArray, array[i])
}
return combineArray
}
// rangeFrom like range in python, default step is 1.
func rangeFrom[T constraints.Integer](s, e T) []T {
_a := make([]T, 0, e-s)
for i := s; i < e; i++ {
_a = append(_a, i)
}
return _a
}
// reverseArray like reverse in python.
func reverseArray[T comparable](a []T) []T {
i := 0
j := len(a) - 1
for i < j {
a[i], a[j] = a[j], a[i]
i++
j--
}
return a
}
// reverseArray like reverse in python.
func reverseArrayNoChange[T comparable](a []T) []T {
b := make([]T, len(a))
copy(b, a)
return reverseArray(b)
}