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
}
|