-
Notifications
You must be signed in to change notification settings - Fork 0
/
list.go
252 lines (207 loc) · 6.23 KB
/
list.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
package binoislist
import (
"fmt"
"sort"
"strings"
)
// BinoisList is a slice of BinoisPtr.
type BinoisList []BinoisPtr
const UnknownBinois BinoisPtr = -1
// NewBinoisList creates a new BinoisList with some initial items.
func NewBinoisList(items ...BinoisPtr) BinoisList {
return items
}
// Append adds one or more items to the list.
// Don't forget to assign the result to your variable.
// myList = myList.Append(x, y)
func (list BinoisList) Append(items ...BinoisPtr) BinoisList {
return append(list, items...)
}
// Cat concatenates multiple lists into a single list.
// Don't forget to assign the result to your variable.
// myList = myList.Cat(l1, l2)
func (list BinoisList) Cat(inputLists ...BinoisList) BinoisList {
for _, oneList := range inputLists {
list = append(list, oneList...)
}
return list
}
// Join converts all the items in a BinoisList to strings and joins them with a
// separator. Default separator is ", ".
func (list BinoisList) Join(seps ...string) string {
sep := ", "
if len(seps) > 0 {
sep = seps[0]
}
var collector []string
for _, item := range list {
// %#v will invoke String() if exists on the item.
collector = append(collector, fmt.Sprintf("%#v", item))
}
return strings.Join(collector, sep)
}
// Len returns the number of elements in the list
func (list BinoisList) Len() int {
return len(list)
}
// Get returns the item at position i.
func (list BinoisList) Get(i int) BinoisPtr {
return list[i]
}
// GetOrUnknown returns the element as position i, or unknown if out of range.
func (list BinoisList) GetOrUnknown(i int) (BinoisPtr, error) {
if i < 0 || i >= len(list) {
return UnknownBinois, fmt.Errorf("out of range")
}
return list[i], nil
}
// BinoisMapperFunc processes a BinoisPtr and returns a BinoisPtr.
type BinoisMapperFunc func(g BinoisPtr) BinoisPtr
func (list BinoisList) Map(f BinoisMapperFunc) BinoisList {
var newList BinoisList
for _, item := range list {
newList = append(newList, f(item))
}
return newList
}
// BinoisTesterFunc is a function that returns true/false given a BinoisPtr. Used
// for finding or filtering with a BinoisList.
type BinoisTesterFunc func(g BinoisPtr) bool
// Filter returns a new BinoisList of items where f() is true.
func (list BinoisList) Filter(f BinoisTesterFunc) BinoisList {
var newList BinoisList
for _, item := range list {
if f(item) {
newList = append(newList, item)
}
}
return newList
}
// First returns the first BinoisPtr where f() is true.
func (list BinoisList) First(f BinoisTesterFunc) (item BinoisPtr, found bool) {
for _, item := range list {
if f(item) {
return item, true
}
}
return UnknownBinois, false
}
// BinoisLessThanFunc is a function that compares two items of type BinoisPtr.
type BinoisLessThanFunc func(a, b BinoisPtr) bool
// Sort sorts IN PLACE a BinoisList with the input comparer function.
func (list BinoisList) Sort(f BinoisLessThanFunc) BinoisList {
sort.Slice(list, func(i, j int) bool {
return f(list[i], list[j])
})
return list
}
// Copy returns a BinoisList containing the contents of the list.
func (list BinoisList) Copy() BinoisList {
newList := make(BinoisList, len(list))
copy(newList, list)
return newList
}
// BinoisEqualizer provides an Equals method for items of type BinoisPtr.
type BinoisEqualizer interface {
Equals(BinoisPtr) bool
}
// Equalizer handles type conversion. This is a workaround to allow users
// of this package to partially implement requirements.
func (thing BinoisPtr) Equalizer() BinoisEqualizer {
var x interface{} = thing
return x.(BinoisEqualizer)
}
// affirmBinoisEqualsImplemented exists to output a more meaningful error when
// the Equals method has not been implemented. We could have just done type
// assertions w/o checking and had the same net result (panic), but having a
// better explanation is better.
func affirmBinoisEqualsImplemented(methodName string) {
var t BinoisPtr
var x interface{} = t
_, ok := x.(BinoisEqualizer)
if !ok {
panic("implement method BinoisPtr.Equals(BinoisPtr) in order to use " + methodName)
}
}
// Index returns the position of item in the list, and if found.
// Method Equals(BinoisPtr) must be implemented.
func (list BinoisList) Index(item BinoisPtr) (int, bool) {
affirmBinoisEqualsImplemented("BinoisList.Index(item)")
eqItem := item.Equalizer()
for pos, item := range list {
if eqItem.Equals(item) {
return pos, true
}
}
return -1, false
}
// LastIndex returns the position of item in the list, and if found.
// Method Equals(BinoisPtr) must be implemented.
func (list BinoisList) LastIndex(item BinoisPtr) (int, bool) {
affirmBinoisEqualsImplemented("BinoisList.LastIndex(item)")
eqItem := item.Equalizer()
for pos := len(list) - 1; pos >= 0; pos-- {
if eqItem.Equals(list[pos]) {
return pos, true
}
}
return -1, false
}
// Equals checks if two BinoisList instances are equal by comparing all their
// elements with the BinoisPtr Equals method.
func (list BinoisList) Equals(other BinoisList) bool {
affirmBinoisEqualsImplemented("BinoisList.Equals()")
if list.Len() != other.Len() {
return false
}
for i := range list {
eqItem := list[i].Equalizer()
if !eqItem.Equals(other[i]) {
return false
}
}
return true
}
// Delete returns a new list with one element omitted.
func (list BinoisList) Delete(index int) BinoisList {
if len(list)+index < 0 {
return list.Copy()
}
index = list.cleanIndex(index)
return list.DeletePart(index, index+1)
}
// cleanIndex is a helper method to ensure offsets are within range.
func (list BinoisList) cleanIndex(i int) int {
if i > len(list) {
return len(list)
}
if i < 0 {
i = len(list) + i
if i < 0 {
return 0
}
return i
}
return i
}
// DeletePart returns a new BinoisList with a portion omitted.
func (list BinoisList) DeletePart(first, last int) BinoisList {
first = list.cleanIndex(first)
last = list.cleanIndex(last)
if first >= last {
return list.Copy()
}
var newList BinoisList
newList = append(newList, list[0:first]...)
newList = append(newList, list[last:]...)
return newList
}
// Part returns a portion of a BinoisList as a new list.
func (list BinoisList) Part(first, last int) BinoisList {
first = list.cleanIndex(first)
last = list.cleanIndex(last)
if first >= last {
return NewBinoisList()
}
return list[first:last]
}