| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- // 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
- // Interface is describing a Set. Sets are an unordered, unique list of values.
- type Interface interface {
- New(items ...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{}{}
- // 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
- }
|