github.com/mitranim/gg@v0.1.17/set.go (about) 1 package gg 2 3 import "encoding/json" 4 5 /* 6 Syntactic shortcut for making a set from a slice, with element type inference 7 and capacity preallocation. Always returns non-nil, even if the input is 8 empty. 9 */ 10 func SetOf[A comparable](val ...A) Set[A] { 11 return make(Set[A], len(val)).Add(val...) 12 } 13 14 /* 15 Syntactic shortcut for making a set from multiple slices, with element type 16 inference and capacity preallocation. Always returns non-nil, even if the input 17 is empty. 18 */ 19 func SetFrom[Slice ~[]Elem, Elem comparable](val ...Slice) Set[Elem] { 20 buf := make(Set[Elem], Lens(val...)) 21 for _, val := range val { 22 buf.Add(val...) 23 } 24 return buf 25 } 26 27 /* 28 Creates a set by "mapping" the elements of a given slice via the provided 29 function. Always returns non-nil, even if the input is empty. 30 */ 31 func SetMapped[Elem any, Val comparable](src []Elem, fun func(Elem) Val) Set[Val] { 32 buf := make(Set[Val], len(src)) 33 if fun != nil { 34 for _, val := range src { 35 buf[fun(val)] = struct{}{} 36 } 37 } 38 return buf 39 } 40 41 // Generic unordered set backed by a map. 42 type Set[A comparable] map[A]struct{} 43 44 /* 45 Idempotently inits the map via `make`, making it writable. The output pointer 46 must be non-nil. 47 */ 48 func (self *Set[A]) Init() Set[A] { 49 if *self == nil { 50 *self = make(Set[A]) 51 } 52 return *self 53 } 54 55 // Same as `len(set)`. Nil-safe. 56 func (self Set[_]) Len() int { return len(self) } 57 58 // True if the set includes the given value. Nil-safe. 59 func (self Set[A]) Has(val A) bool { return MapHas(self, val) } 60 61 // Idempotently adds the given values to the receiver, which must be non-nil. 62 func (self Set[A]) Add(val ...A) Set[A] { 63 for _, val := range val { 64 self[val] = struct{}{} 65 } 66 return self 67 } 68 69 /* 70 Set union. Idempotently adds all values from the given source sets to the 71 receiver, which must be non-nil. 72 */ 73 func (self Set[A]) AddFrom(val ...Set[A]) Set[A] { 74 for _, val := range val { 75 for val := range val { 76 self[val] = struct{}{} 77 } 78 } 79 return self 80 } 81 82 // Deletes the given values from the receiver, which may be nil. 83 func (self Set[A]) Del(val ...A) Set[A] { 84 for _, val := range val { 85 delete(self, val) 86 } 87 return self 88 } 89 90 /* 91 Deletes all values present in the given source sets from the receiver, which may 92 be nil. 93 */ 94 func (self Set[A]) DelFrom(val ...Set[A]) Set[A] { 95 for _, val := range val { 96 for val := range val { 97 delete(self, val) 98 } 99 } 100 return self 101 } 102 103 /* 104 Clears and returns the receiver, which may be nil. Note that this type is 105 implemented as a map, and this method involves iterating the map, which is 106 inefficient in Go. In many cases, it's more efficient to make a new set. 107 */ 108 func (self Set[A]) Clear() Set[A] { 109 for val := range self { 110 delete(self, val) 111 } 112 return self 113 } 114 115 // Combination of `Set.Clear` and `Set.Add`. 116 func (self Set[A]) Reset(val ...A) Set[A] { 117 self.Clear() 118 self.Add(val...) 119 return self 120 } 121 122 // Converts the map to a slice of its values. Order is random. 123 func (self Set[A]) Slice() []A { return MapKeys(self) } 124 125 /* 126 Returns the subset of values for which the given function returns true. 127 Order is random. If function is nil, output is nil. 128 */ 129 func (self Set[A]) Filter(fun func(A) bool) []A { 130 var out []A 131 if fun != nil { 132 for val := range self { 133 if fun(val) { 134 out = append(out, val) 135 } 136 } 137 } 138 return out 139 } 140 141 // JSON-encodes as a list. Order is random. 142 func (self Set[A]) MarshalJSON() ([]byte, error) { 143 return json.Marshal(self.Slice()) 144 } 145 146 /* 147 JSON-decodes the input, which must either represent JSON "null" or a JSON list 148 of values compatible with the value type. 149 */ 150 func (self *Set[A]) UnmarshalJSON(src []byte) error { 151 var buf []A 152 err := json.Unmarshal(src, &buf) 153 if err != nil { 154 return err 155 } 156 157 self.Init().Reset(buf...) 158 return nil 159 } 160 161 // Implement `fmt.GoStringer`, returning valid Go code that constructs the set. 162 func (self Set[A]) GoString() string { 163 typ := TypeOf(self).String() 164 165 if self == nil { 166 return typ + `(nil)` 167 } 168 169 if len(self) <= 0 { 170 return typ + `{}` 171 } 172 173 var buf Buf 174 buf.AppendString(typ) 175 buf.AppendString(`{}.Add(`) 176 177 var found bool 178 for val := range self { 179 if found { 180 buf.AppendString(`, `) 181 } 182 found = true 183 buf.AppendGoString(val) 184 } 185 186 buf.AppendString(`)`) 187 return buf.String() 188 }