-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpairs.go
261 lines (223 loc) · 6.36 KB
/
pairs.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
package geko
import "sort"
// Pairs is a wrapper type of [][Pair][K, V].
//
// In JSON unmarshal, it will use the order of appearance in input JSON data,
// and marshal output will use the same order. But differ from [Map], it saves
// all items when their key is duplicated.
//
// When unmarshal from JSON into a [ObjectItems], all JSON object will be
// stored in [ObjectItems], all JSON array will be stored in [Array],
// instead of normal map[string]any and []any from std lib.
//
// Notice: Although this type behaves like a [Map], because it is only a slice
// internally, the performance of some APIs are not very good. It is best to
// keep this in mind when using it.
type Pairs[K comparable, V any] struct {
List []Pair[K, V]
}
// ObjectItems is [Pairs] whose type parameters are specialized as
// [string, any], used to represent dynamic objects in JSON.
type ObjectItems = *Pairs[string, any]
// NewPairs creates a new empty list.
func NewPairs[K comparable, V any]() *Pairs[K, V] {
return NewPairsFrom[K, V](nil)
}
// NewPairsWithCapacity likes [NewPairs], but init the inner container
// with a capacity to optimize memory allocate.
func NewPairsWithCapacity[K comparable, V any](capacity int) *Pairs[K, V] {
return NewPairsFrom[K, V](make([]Pair[K, V], 0, capacity))
}
// NewPairsFrom create a List from a slice.
func NewPairsFrom[K comparable, V any](list []Pair[K, V]) *Pairs[K, V] {
return &Pairs[K, V]{
List: list,
}
}
// Get values by key.
//
// Performance: O(n)
func (ps *Pairs[K, V]) Get(key K) []V {
var values []V
for i := range ps.List {
p := &ps.List[i]
if key == p.Key {
values = append(values, p.Value)
}
}
return values
}
// Has checks if a key exist in the list.
//
// Performance: O(n)
func (ps *Pairs[K, V]) Has(key K) bool {
for i := range ps.List {
if key == ps.List[i].Key {
return true
}
}
return false
}
// Count get appear times of a key.
//
// Performance: O(n)
func (ps *Pairs[K, V]) Count(key K) int {
n := 0
for i := range ps.List {
if key == ps.List[i].Key {
n++
}
}
return n
}
// GetFirstOrZeroValue get first value by key, return a zero value of type V if
// key doesn't exist in list.
//
// Performance: O(n)
func (ps *Pairs[K, V]) GetFirstOrZeroValue(key K) (value V) {
for i := range ps.List {
p := &ps.List[i]
if key == p.Key {
value = p.Value
break
}
}
return
}
// GetLastOrZeroValue get last value by key, return a zero value of type V if
// key doesn't exist in list.
//
// Performance: O(n)
func (ps *Pairs[K, V]) GetLastOrZeroValue(key K) (value V) {
for i := ps.Len() - 1; i >= 0; i-- {
p := &ps.List[i]
if key == p.Key {
value = p.Value
break
}
}
return
}
// GetKeyByIndex get key at index.
//
// You should make sure 0 <= i < Len(), panic if out of bound.
func (ps *Pairs[K, V]) GetKeyByIndex(index int) K {
return ps.List[index].Key
}
// GetByIndex get key value pair at index.
//
// You should make sure 0 <= i < Len(), panic if out of bound.
func (ps *Pairs[K, V]) GetByIndex(index int) Pair[K, V] {
return ps.List[index]
}
// GetValueByIndex get value at index.
//
// You should make sure 0 <= i < Len(), panic if out of bound.
func (ps *Pairs[K, V]) GetValueByIndex(index int) V {
return ps.List[index].Value
}
// SetKeyByIndex changes key of item at index.
func (ps *Pairs[K, V]) SetKeyByIndex(index int, key K) {
ps.List[index].Key = key
}
// SetValueByIndex changes value of item at index.
func (ps *Pairs[K, V]) SetValueByIndex(index int, value V) {
ps.List[index].Value = value
}
// SetByIndex key and value at index.
func (ps *Pairs[K, V]) SetByIndex(index int, key K, value V) {
ps.List[index] = CreatePair(key, value)
}
// Add a key value pair to the end of list.
func (ps *Pairs[K, V]) Add(key K, value V) {
ps.List = append(ps.List, CreatePair(key, value))
}
// Append some key value pairs to the end of list.
func (ps *Pairs[K, V]) Append(pairs ...Pair[K, V]) {
ps.List = append(ps.List, pairs...)
}
// Delete all item whose key is same as provided.
//
// Performance: O(n)
func (ps *Pairs[K, V]) Delete(key K) {
ps.Filter(func(p *Pair[K, V]) bool {
return p.Key != key
})
}
// DeleteByIndex delete item at index.
//
// Performance: O(n)
func (ps *Pairs[K, V]) DeleteByIndex(index int) {
ps.List = append(ps.List[:index], ps.List[index+1:]...)
}
// Clear this list.
func (ps *Pairs[K, V]) Clear() {
ps.List = nil
}
// Len returns the size of list.
func (ps *Pairs[K, V]) Len() int {
return len(ps.List)
}
// Keys returns all keys of the list.
//
// Performance: O(n).
func (ps *Pairs[K, V]) Keys() []K {
keys := make([]K, 0, ps.Len())
for i, length := 0, ps.Len(); i < length; i++ {
keys = append(keys, ps.GetKeyByIndex(i))
}
return keys
}
// Values returns all values of the list.
//
// Performance: O(n).
func (ps *Pairs[K, V]) Values() []V {
values := make([]V, 0, ps.Len())
for i, length := 0, ps.Len(); i < length; i++ {
values = append(values, ps.GetValueByIndex(i))
}
return values
}
// ToMap convert this list into a [Map], with provided [DuplicatedKeyStrategy].
func (ps *Pairs[K, V]) ToMap(strategy DuplicatedKeyStrategy) *Map[K, V] {
m := NewMap[K, V]()
m.SetDuplicatedKeyStrategy(strategy)
m.Append(ps.List...)
return m
}
// Dedup deduplicates this list by key.
//
// Implemented as converting it to a [Map] and back.
func (ps *Pairs[K, V]) Dedup(strategy DuplicatedKeyStrategy) {
ps.List = ps.ToMap(strategy).Pairs().List
}
// Sort will reorder the list using the given less function.
func (ps *Pairs[K, V]) Sort(lessFunc PairLessFunc[K, V]) {
sort.SliceStable(ps.List, func(i, j int) bool {
return lessFunc(&ps.List[i], &ps.List[j])
})
}
// Filter remove all item which make pred func return false.
//
// Performance: O(n). More efficient then [Pairs.GetByIndex] +
// [Pairs.DeleteByIndex] in a loop, which is O(n^2).
func (ps *Pairs[K, V]) Filter(pred PairFilterFunc[K, V]) {
n := 0
for i, length := 0, ps.Len(); i < length; i++ {
if pred(&ps.List[i]) {
ps.List[n] = ps.List[i]
n++
}
}
ps.List = ps.List[:n]
}
// MarshalJSON implements json.Marshaler interface.
// You should not call this directly, use json.Marshal(m) instead.
func (ps Pairs[K, V]) MarshalJSON() ([]byte, error) {
return marshalObject[K, V](&ps)
}
// UnmarshalJSON implements json.Unmarshaler interface.
// You shouldn't call this directly, use json.Unmarshal(m) instead.
func (ps *Pairs[K, V]) UnmarshalJSON(data []byte) error {
return unmarshalObject[K, V](data, ps, UseObjectItems())
}