This repository has been archived by the owner on Aug 3, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 85
/
set.go
148 lines (131 loc) · 3.74 KB
/
set.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
// Package set provides both threadsafe and non-threadsafe implementations of
// a generic set data structure. In the threadsafe set, safety encompasses all
// operations on one set. Operations on multiple sets are consistent in that
// the elements of each set used was valid at exactly one point in time
// between the start and the end of the operation.
package set
// SetType denotes which type of set is created. ThreadSafe or NonThreadSafe
type SetType int
const (
ThreadSafe = iota
NonThreadSafe
)
func (s SetType) String() string {
switch s {
case ThreadSafe:
return "ThreadSafe"
case NonThreadSafe:
return "NonThreadSafe"
}
return ""
}
// Interface is describing a Set. Sets are an unordered, unique list of values.
type Interface interface {
Add(items ...interface{})
Remove(items ...interface{})
Pop() interface{}
Has(items ...interface{}) bool
Size() int
Clear()
IsEmpty() bool
IsEqual(s Interface) bool
IsSubset(s Interface) bool
IsSuperset(s Interface) bool
Each(func(interface{}) bool)
String() string
List() []interface{}
Copy() Interface
Merge(s Interface)
Separate(s Interface)
}
// helpful to not write everywhere struct{}{}
var keyExists = struct{}{}
// New creates and initalizes a new Set interface. Its single parameter
// denotes the type of set to create. Either ThreadSafe or
// NonThreadSafe. The default is ThreadSafe.
func New(settype SetType) Interface {
if settype == NonThreadSafe {
return newNonTS()
}
return newTS()
}
// Union is the merger of multiple sets. It returns a new set with all the
// elements present in all the sets that are passed.
//
// The dynamic type of the returned set is determined by the first passed set's
// implementation of the New() method.
func Union(set1, set2 Interface, sets ...Interface) Interface {
u := set1.Copy()
set2.Each(func(item interface{}) bool {
u.Add(item)
return true
})
for _, set := range sets {
set.Each(func(item interface{}) bool {
u.Add(item)
return true
})
}
return u
}
// Difference returns a new set which contains items which are in in the first
// set but not in the others. Unlike the Difference() method you can use this
// function separately with multiple sets.
func Difference(set1, set2 Interface, sets ...Interface) Interface {
s := set1.Copy()
s.Separate(set2)
for _, set := range sets {
s.Separate(set) // seperate is thread safe
}
return s
}
// Intersection returns a new set which contains items that only exist in all given sets.
func Intersection(set1, set2 Interface, sets ...Interface) Interface {
all := Union(set1, set2, sets...)
result := Union(set1, set2, sets...)
all.Each(func(item interface{}) bool {
if !set1.Has(item) || !set2.Has(item) {
result.Remove(item)
}
for _, set := range sets {
if !set.Has(item) {
result.Remove(item)
}
}
return true
})
return result
}
// SymmetricDifference returns a new set which s is the difference of items which are in
// one of either, but not in both.
func SymmetricDifference(s Interface, t Interface) Interface {
u := Difference(s, t)
v := Difference(t, s)
return Union(u, v)
}
// StringSlice is a helper function that returns a slice of strings of s. If
// the set contains mixed types of items only items of type string are returned.
func StringSlice(s Interface) []string {
slice := make([]string, 0)
for _, item := range s.List() {
v, ok := item.(string)
if !ok {
continue
}
slice = append(slice, v)
}
return slice
}
// IntSlice is a helper function that returns a slice of ints of s. If
// the set contains mixed types of items only items of type int are returned.
func IntSlice(s Interface) []int {
slice := make([]int, 0)
for _, item := range s.List() {
v, ok := item.(int)
if !ok {
continue
}
slice = append(slice, v)
}
return slice
}