-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmapset.go
257 lines (229 loc) · 5.65 KB
/
mapset.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
// Package mapset implements a basic set type using a built-in map.
//
// The Set type is a thin wrapper on a built-in Go map, so a Set is not safe
// for concurrent use without external synchronization.
package mapset
import (
"iter"
"maps"
)
// A Set represents a set of distinct values. It is implemented via the
// built-in map type, and the underlying map can also be used directly to add
// and remove items and to iterate the contents.
type Set[T comparable] map[T]struct{}
// New constructs a set of the specified items. The result is never nil, even
// if no items are provided.
func New[T comparable](items ...T) Set[T] {
m := make(Set[T], len(items))
return m.add(items)
}
// NewSize constructs a new empty set preallocated to have space for n items.
func NewSize[T comparable](n int) Set[T] { return make(Set[T], n) }
// IsEmpty reports whether s is empty.
func (s Set[T]) IsEmpty() bool { return len(s) == 0 }
// Len reports the number of elements in s.
func (s Set[T]) Len() int { return len(s) }
// Clear removes all elements from s and returns s.
func (s Set[T]) Clear() Set[T] { clear(s); return s }
// Clone returns a new set with the same contents as s.
// The value returned is never nil.
func (s Set[T]) Clone() Set[T] {
if s == nil {
return make(Set[T])
}
// N.B. maps.Clone uses a runtime API internally so it should generally
// always be more efficient than an explicit copy.
return maps.Clone(s)
}
// Has reports whether t is present in the set.
func (s Set[T]) Has(t T) bool { _, ok := s[t]; return ok }
// Add adds the specified items to the set and returns s.
func (s *Set[T]) Add(items ...T) Set[T] {
if *s == nil {
*s = make(Set[T], len(items))
}
return (*s).add(items)
}
func (s Set[T]) add(items []T) Set[T] {
for _, item := range items {
s[item] = struct{}{}
}
return s
}
// AddAll adds all the elements of set t to s and returns s.
func (s *Set[T]) AddAll(t Set[T]) Set[T] {
if *s == nil {
*s = t.Clone()
return *s
}
for item := range t {
(*s)[item] = struct{}{}
}
return *s
}
// Remove removes the specified items from the set and returns s.
func (s Set[T]) Remove(items ...T) Set[T] {
for _, item := range items {
if len(s) == 0 {
break
}
delete(s, item)
}
return s
}
// RemoveAll removes all the elements of set t from s and returns s.
func (s Set[T]) RemoveAll(t Set[T]) Set[T] {
for item := range t {
if len(s) == 0 {
break
}
delete(s, item)
}
return s
}
// Pop removes and returns an arbitrary element of s, if s is non-empty.
// If s is empty, it returns a zero value.
func (s Set[T]) Pop() T {
for item := range s {
delete(s, item)
return item
}
var zero T
return zero
}
// Intersects reports whether s and t share any elements in common.
func (s Set[T]) Intersects(t Set[T]) bool {
lo, hi := s, t
if len(s) > len(t) {
lo, hi = hi, lo
}
for item := range lo {
if hi.Has(item) {
return true
}
}
return false
}
// HasAll reports whether s contains all the elements of ts.
// It is semantically equivalent to ts.IsSubset(s), but does not construct an
// intermediate set. It returns true if len(ts) == 0.
func (s Set[T]) HasAll(ts ...T) bool {
if len(s) == 0 {
return len(ts) == 0
}
for _, t := range ts {
if !s.Has(t) {
return false
}
}
return true
}
// HasAny reports whether s contains any element of ts.
// It is semantically equivalent to ts.Intersects(s), but does not construct an
// intermediate set. It returns false if len(ts) == 0.
func (s Set[T]) HasAny(ts ...T) bool {
if len(s) == 0 {
return false
}
for _, t := range ts {
if s.Has(t) {
return true
}
}
return false
}
// IsSubset reports whether s is a subset of t.
func (s Set[T]) IsSubset(t Set[T]) bool {
if len(s) == 0 {
return true
} else if len(s) > len(t) {
return false
}
for item := range s {
if !t.Has(item) {
return false
}
}
return true
}
// Equals reports whether s and t contain exactly the same elements.
func (s Set[T]) Equals(t Set[T]) bool {
if len(s) != len(t) {
return false
}
for item := range s {
if !t.Has(item) {
return false
}
}
return true
}
// Append appends the elements of s to the specified slice in arbitrary order,
// and returns the resulting slice. If cap(vs) ≥ len(s) this will not allocate.
func (s Set[T]) Append(vs []T) []T {
if len(s) == 0 {
return vs
}
for item := range s {
vs = append(vs, item)
}
return vs
}
// Slice returns a slice of the contents of s in arbitrary order.
// It is a shorthand for Append.
func (s Set[T]) Slice() []T {
if len(s) == 0 {
return nil
}
return s.Append(make([]T, 0, len(s)))
}
// Intersect constructs a new set containing the intersection of the specified
// sets. The result is never nil, even if the given sets are empty.
func Intersect[T comparable](ss ...Set[T]) Set[T] {
if len(ss) == 0 {
return make(Set[T])
}
min := ss[0]
for _, s := range ss[1:] {
if len(s) < len(min) {
min = s
}
}
out := make(Set[T], len(min))
nextElt:
for v := range min {
for _, s := range ss {
if !s.Has(v) {
continue nextElt
}
}
out.Add(v)
}
return out
}
// Range constructs a new Set containing the values of it.
func Range[T comparable](it iter.Seq[T]) Set[T] {
out := make(Set[T])
for v := range it {
out.Add(v)
}
return out
}
// Keys constructs a new Set containing the keys of m. The result is never
// nil, even if m is empty.
func Keys[T comparable, U any](m map[T]U) Set[T] {
out := make(Set[T], len(m))
for key := range m {
out.Add(key)
}
return out
}
// Values constructs a new Set containing the values of m. The result is never
// nil, even if m is empty.
func Values[T, U comparable](m map[T]U) Set[U] {
out := make(Set[U])
for _, val := range m {
out.Add(val)
}
return out
}