github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/sets/linkedhashset/linkedhashset.go (about) 1 // Package linkedhashset is a set that preserves insertion-order. 2 // 3 // It is backed by a hash table to store values and doubly-linked list to store ordering. 4 // 5 // Note that insertion-order is not affected if an element is re-inserted into the set. 6 // 7 // Structure is not thread safe. 8 // 9 // References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 10 package linkedhashset 11 12 import ( 13 "encoding/json" 14 "fmt" 15 "strings" 16 17 "github.com/songzhibin97/go-baseutils/structure/lists/doublylinkedlist" 18 "github.com/songzhibin97/go-baseutils/structure/sets" 19 ) 20 21 // Assert Set implementation 22 var _ sets.Set[int] = (*Set[int])(nil) 23 24 // Set holds elements in go's native map 25 type Set[E comparable] struct { 26 table map[E]struct{} 27 ordering *doublylinkedlist.List[E] 28 zero E 29 } 30 31 var itemExists = struct{}{} 32 33 // New instantiates a new empty set and adds the passed values, if any, to the set 34 func New[E comparable](values ...E) *Set[E] { 35 set := &Set[E]{ 36 table: make(map[E]struct{}), 37 ordering: doublylinkedlist.New[E](), 38 } 39 if len(values) > 0 { 40 set.Add(values...) 41 } 42 return set 43 } 44 45 // Add adds the items (one or more) to the set. 46 // Note that insertion-order is not affected if an element is re-inserted into the set. 47 func (set *Set[E]) Add(items ...E) { 48 for _, item := range items { 49 if _, contains := set.table[item]; !contains { 50 set.table[item] = itemExists 51 set.ordering.Append(item) 52 } 53 } 54 } 55 56 // Remove removes the items (one or more) from the set. 57 // Slow operation, worst-case O(n^2). 58 func (set *Set[E]) Remove(items ...E) { 59 for _, item := range items { 60 if _, contains := set.table[item]; contains { 61 delete(set.table, item) 62 index := set.ordering.IndexOf(item) 63 set.ordering.Remove(index) 64 } 65 } 66 } 67 68 // Contains check if items (one or more) are present in the set. 69 // All items have to be present in the set for the method to return true. 70 // Returns true if no arguments are passed at all, i.e. set is always superset of empty set. 71 func (set *Set[E]) Contains(items ...E) bool { 72 for _, item := range items { 73 if _, contains := set.table[item]; !contains { 74 return false 75 } 76 } 77 return true 78 } 79 80 // Empty returns true if set does not contain any elements. 81 func (set *Set[E]) Empty() bool { 82 return set.Size() == 0 83 } 84 85 // Size returns number of elements within the set. 86 func (set *Set[E]) Size() int { 87 return set.ordering.Size() 88 } 89 90 // Clear clears all values in the set. 91 func (set *Set[E]) Clear() { 92 set.table = make(map[E]struct{}) 93 set.ordering.Clear() 94 } 95 96 // Values returns all items in the set. 97 func (set *Set[E]) Values() []E { 98 values := make([]E, set.Size()) 99 it := set.Iterator() 100 for it.Next() { 101 values[it.Index()] = it.Value() 102 } 103 return values 104 } 105 106 // String returns a string representation of container 107 func (set *Set[E]) String() string { 108 b := strings.Builder{} 109 b.WriteString("LinkedHashSet\n") 110 it := set.Iterator() 111 for it.Next() { 112 b.WriteString(fmt.Sprintf("(key:%v) ", it.Value())) 113 } 114 return b.String() 115 } 116 117 // Intersection returns the intersection between two sets. 118 // The new set consists of all elements that are both in "set" and "another". 119 // Ref: https://en.wikipedia.org/wiki/Intersection_(set_theory) 120 func (set *Set[E]) Intersection(another *Set[E]) *Set[E] { 121 result := New[E]() 122 123 // Iterate over smaller set (optimization) 124 if set.Size() <= another.Size() { 125 for item := range set.table { 126 if _, contains := another.table[item]; contains { 127 result.Add(item) 128 } 129 } 130 } else { 131 for item := range another.table { 132 if _, contains := set.table[item]; contains { 133 result.Add(item) 134 } 135 } 136 } 137 138 return result 139 } 140 141 // Union returns the union of two sets. 142 // The new set consists of all elements that are in "set" or "another" (possibly both). 143 // Ref: https://en.wikipedia.org/wiki/Union_(set_theory) 144 func (set *Set[E]) Union(another *Set[E]) *Set[E] { 145 result := New[E]() 146 147 for item := range set.table { 148 result.Add(item) 149 } 150 for item := range another.table { 151 result.Add(item) 152 } 153 154 return result 155 } 156 157 // Difference returns the difference between two sets. 158 // The new set consists of all elements that are in "set" but not in "another". 159 // Ref: https://proofwiki.org/wiki/Definition:Set_Difference 160 func (set *Set[E]) Difference(another *Set[E]) *Set[E] { 161 result := New[E]() 162 163 for item := range set.table { 164 if _, contains := another.table[item]; !contains { 165 result.Add(item) 166 } 167 } 168 169 return result 170 } 171 172 // UnmarshalJSON @implements json.Unmarshaler 173 func (set *Set[E]) UnmarshalJSON(bytes []byte) error { 174 elements := []E{} 175 err := json.Unmarshal(bytes, &elements) 176 if err == nil { 177 set.Clear() 178 set.Add(elements...) 179 } 180 return err 181 } 182 183 // MarshalJSON @implements json.Marshaler 184 func (set *Set[E]) MarshalJSON() ([]byte, error) { 185 return json.Marshal(set.Values()) 186 }