set.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Package set provides both threadsafe and non-threadsafe implementations of
  2. // a generic set data structure. In the threadsafe set, safety encompasses all
  3. // operations on one set. Operations on multiple sets are consistent in that
  4. // the elements of each set used was valid at exactly one point in time
  5. // between the start and the end of the operation.
  6. package set
  7. // Interface is describing a Set. Sets are an unordered, unique list of values.
  8. type Interface interface {
  9. New(items ...interface{}) Interface
  10. Add(items ...interface{})
  11. Remove(items ...interface{})
  12. Pop() interface{}
  13. Has(items ...interface{}) bool
  14. Size() int
  15. Clear()
  16. IsEmpty() bool
  17. IsEqual(s Interface) bool
  18. IsSubset(s Interface) bool
  19. IsSuperset(s Interface) bool
  20. Each(func(interface{}) bool)
  21. String() string
  22. List() []interface{}
  23. Copy() Interface
  24. Merge(s Interface)
  25. Separate(s Interface)
  26. }
  27. // helpful to not write everywhere struct{}{}
  28. var keyExists = struct{}{}
  29. // Union is the merger of multiple sets. It returns a new set with all the
  30. // elements present in all the sets that are passed.
  31. //
  32. // The dynamic type of the returned set is determined by the first passed set's
  33. // implementation of the New() method.
  34. func Union(set1, set2 Interface, sets ...Interface) Interface {
  35. u := set1.Copy()
  36. set2.Each(func(item interface{}) bool {
  37. u.Add(item)
  38. return true
  39. })
  40. for _, set := range sets {
  41. set.Each(func(item interface{}) bool {
  42. u.Add(item)
  43. return true
  44. })
  45. }
  46. return u
  47. }
  48. // Difference returns a new set which contains items which are in in the first
  49. // set but not in the others. Unlike the Difference() method you can use this
  50. // function separately with multiple sets.
  51. func Difference(set1, set2 Interface, sets ...Interface) Interface {
  52. s := set1.Copy()
  53. s.Separate(set2)
  54. for _, set := range sets {
  55. s.Separate(set) // seperate is thread safe
  56. }
  57. return s
  58. }
  59. // Intersection returns a new set which contains items that only exist in all given sets.
  60. func Intersection(set1, set2 Interface, sets ...Interface) Interface {
  61. all := Union(set1, set2, sets...)
  62. result := Union(set1, set2, sets...)
  63. all.Each(func(item interface{}) bool {
  64. if !set1.Has(item) || !set2.Has(item) {
  65. result.Remove(item)
  66. }
  67. for _, set := range sets {
  68. if !set.Has(item) {
  69. result.Remove(item)
  70. }
  71. }
  72. return true
  73. })
  74. return result
  75. }
  76. // SymmetricDifference returns a new set which s is the difference of items which are in
  77. // one of either, but not in both.
  78. func SymmetricDifference(s Interface, t Interface) Interface {
  79. u := Difference(s, t)
  80. v := Difference(t, s)
  81. return Union(u, v)
  82. }
  83. // StringSlice is a helper function that returns a slice of strings of s. If
  84. // the set contains mixed types of items only items of type string are returned.
  85. func StringSlice(s Interface) []string {
  86. slice := make([]string, 0)
  87. for _, item := range s.List() {
  88. v, ok := item.(string)
  89. if !ok {
  90. continue
  91. }
  92. slice = append(slice, v)
  93. }
  94. return slice
  95. }
  96. // IntSlice is a helper function that returns a slice of ints of s. If
  97. // the set contains mixed types of items only items of type int are returned.
  98. func IntSlice(s Interface) []int {
  99. slice := make([]int, 0)
  100. for _, item := range s.List() {
  101. v, ok := item.(int)
  102. if !ok {
  103. continue
  104. }
  105. slice = append(slice, v)
  106. }
  107. return slice
  108. }