1*46c4c49dSIbrahim Kanouche// Copyright 2017 Google Inc. 2*46c4c49dSIbrahim Kanouche// 3*46c4c49dSIbrahim Kanouche// Licensed under the Apache License, Version 2.0 (the "License"); 4*46c4c49dSIbrahim Kanouche// you may not use this file except in compliance with the License. 5*46c4c49dSIbrahim Kanouche// You may obtain a copy of the License at 6*46c4c49dSIbrahim Kanouche// 7*46c4c49dSIbrahim Kanouche// http://www.apache.org/licenses/LICENSE-2.0 8*46c4c49dSIbrahim Kanouche// 9*46c4c49dSIbrahim Kanouche// Unless required by applicable law or agreed to in writing, software 10*46c4c49dSIbrahim Kanouche// distributed under the License is distributed on an "AS IS" BASIS, 11*46c4c49dSIbrahim Kanouche// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*46c4c49dSIbrahim Kanouche// See the License for the specific language governing permissions and 13*46c4c49dSIbrahim Kanouche// limitations under the License. 14*46c4c49dSIbrahim Kanouchepackage sets 15*46c4c49dSIbrahim Kanouche 16*46c4c49dSIbrahim Kanoucheimport ( 17*46c4c49dSIbrahim Kanouche "fmt" 18*46c4c49dSIbrahim Kanouche "sort" 19*46c4c49dSIbrahim Kanouche "strings" 20*46c4c49dSIbrahim Kanouche) 21*46c4c49dSIbrahim Kanouche 22*46c4c49dSIbrahim Kanouche// IntSet stores a set of unique int elements. 23*46c4c49dSIbrahim Kanouchetype IntSet struct { 24*46c4c49dSIbrahim Kanouche set map[int]present 25*46c4c49dSIbrahim Kanouche} 26*46c4c49dSIbrahim Kanouche 27*46c4c49dSIbrahim Kanouche// NewIntSet creates an IntSet containing the supplied initial int elements. 28*46c4c49dSIbrahim Kanouchefunc NewIntSet(elements ...int) *IntSet { 29*46c4c49dSIbrahim Kanouche s := &IntSet{} 30*46c4c49dSIbrahim Kanouche s.set = make(map[int]present) 31*46c4c49dSIbrahim Kanouche s.Insert(elements...) 32*46c4c49dSIbrahim Kanouche return s 33*46c4c49dSIbrahim Kanouche} 34*46c4c49dSIbrahim Kanouche 35*46c4c49dSIbrahim Kanouche// Copy returns a newly allocated copy of the supplied IntSet. 36*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Copy() *IntSet { 37*46c4c49dSIbrahim Kanouche c := NewIntSet() 38*46c4c49dSIbrahim Kanouche if s != nil { 39*46c4c49dSIbrahim Kanouche for e := range s.set { 40*46c4c49dSIbrahim Kanouche c.set[e] = present{} 41*46c4c49dSIbrahim Kanouche } 42*46c4c49dSIbrahim Kanouche } 43*46c4c49dSIbrahim Kanouche return c 44*46c4c49dSIbrahim Kanouche} 45*46c4c49dSIbrahim Kanouche 46*46c4c49dSIbrahim Kanouche// Insert zero or more int elements into the IntSet. As expected for a Set, 47*46c4c49dSIbrahim Kanouche// elements already present in the IntSet are simply ignored. 48*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Insert(elements ...int) { 49*46c4c49dSIbrahim Kanouche for _, e := range elements { 50*46c4c49dSIbrahim Kanouche s.set[e] = present{} 51*46c4c49dSIbrahim Kanouche } 52*46c4c49dSIbrahim Kanouche} 53*46c4c49dSIbrahim Kanouche 54*46c4c49dSIbrahim Kanouche// Delete zero or more int elements from the IntSet. Any elements not present 55*46c4c49dSIbrahim Kanouche// in the IntSet are simply ignored. 56*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Delete(elements ...int) { 57*46c4c49dSIbrahim Kanouche for _, e := range elements { 58*46c4c49dSIbrahim Kanouche delete(s.set, e) 59*46c4c49dSIbrahim Kanouche } 60*46c4c49dSIbrahim Kanouche} 61*46c4c49dSIbrahim Kanouche 62*46c4c49dSIbrahim Kanouche// Intersect returns a new IntSet containing the intersection of the receiver 63*46c4c49dSIbrahim Kanouche// and argument IntSets. Returns an empty set if the argument is nil. 64*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Intersect(other *IntSet) *IntSet { 65*46c4c49dSIbrahim Kanouche if other == nil { 66*46c4c49dSIbrahim Kanouche return NewIntSet() 67*46c4c49dSIbrahim Kanouche } 68*46c4c49dSIbrahim Kanouche 69*46c4c49dSIbrahim Kanouche // Point a and b to the maps, setting a to the smaller of the two. 70*46c4c49dSIbrahim Kanouche a, b := s.set, other.set 71*46c4c49dSIbrahim Kanouche if len(b) < len(a) { 72*46c4c49dSIbrahim Kanouche a, b = b, a 73*46c4c49dSIbrahim Kanouche } 74*46c4c49dSIbrahim Kanouche 75*46c4c49dSIbrahim Kanouche // Perform the intersection. 76*46c4c49dSIbrahim Kanouche intersect := NewIntSet() 77*46c4c49dSIbrahim Kanouche for e := range a { 78*46c4c49dSIbrahim Kanouche if _, ok := b[e]; ok { 79*46c4c49dSIbrahim Kanouche intersect.set[e] = present{} 80*46c4c49dSIbrahim Kanouche } 81*46c4c49dSIbrahim Kanouche } 82*46c4c49dSIbrahim Kanouche return intersect 83*46c4c49dSIbrahim Kanouche} 84*46c4c49dSIbrahim Kanouche 85*46c4c49dSIbrahim Kanouche// Disjoint returns true if the intersection of the receiver and the argument 86*46c4c49dSIbrahim Kanouche// IntSets is the empty set. Returns true if the argument is nil or either 87*46c4c49dSIbrahim Kanouche// IntSet is the empty set. 88*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Disjoint(other *IntSet) bool { 89*46c4c49dSIbrahim Kanouche if other == nil || len(other.set) == 0 || len(s.set) == 0 { 90*46c4c49dSIbrahim Kanouche return true 91*46c4c49dSIbrahim Kanouche } 92*46c4c49dSIbrahim Kanouche 93*46c4c49dSIbrahim Kanouche // Point a and b to the maps, setting a to the smaller of the two. 94*46c4c49dSIbrahim Kanouche a, b := s.set, other.set 95*46c4c49dSIbrahim Kanouche if len(b) < len(a) { 96*46c4c49dSIbrahim Kanouche a, b = b, a 97*46c4c49dSIbrahim Kanouche } 98*46c4c49dSIbrahim Kanouche 99*46c4c49dSIbrahim Kanouche // Check for non-empty intersection. 100*46c4c49dSIbrahim Kanouche for e := range a { 101*46c4c49dSIbrahim Kanouche if _, ok := b[e]; ok { 102*46c4c49dSIbrahim Kanouche return false // Early-exit because intersecting. 103*46c4c49dSIbrahim Kanouche } 104*46c4c49dSIbrahim Kanouche } 105*46c4c49dSIbrahim Kanouche return true 106*46c4c49dSIbrahim Kanouche} 107*46c4c49dSIbrahim Kanouche 108*46c4c49dSIbrahim Kanouche// Difference returns a new IntSet containing the elements in the receiver that 109*46c4c49dSIbrahim Kanouche// are not present in the argument IntSet. Returns a copy of the receiver if 110*46c4c49dSIbrahim Kanouche// the argument is nil. 111*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Difference(other *IntSet) *IntSet { 112*46c4c49dSIbrahim Kanouche if other == nil { 113*46c4c49dSIbrahim Kanouche return s.Copy() 114*46c4c49dSIbrahim Kanouche } 115*46c4c49dSIbrahim Kanouche 116*46c4c49dSIbrahim Kanouche // Insert only the elements in the receiver that are not present in the 117*46c4c49dSIbrahim Kanouche // argument IntSet. 118*46c4c49dSIbrahim Kanouche diff := NewIntSet() 119*46c4c49dSIbrahim Kanouche for e := range s.set { 120*46c4c49dSIbrahim Kanouche if _, ok := other.set[e]; !ok { 121*46c4c49dSIbrahim Kanouche diff.set[e] = present{} 122*46c4c49dSIbrahim Kanouche } 123*46c4c49dSIbrahim Kanouche } 124*46c4c49dSIbrahim Kanouche return diff 125*46c4c49dSIbrahim Kanouche} 126*46c4c49dSIbrahim Kanouche 127*46c4c49dSIbrahim Kanouche// Unique returns a new IntSet containing the elements in the receiver that are 128*46c4c49dSIbrahim Kanouche// not present in the argument IntSet *and* the elements in the argument IntSet 129*46c4c49dSIbrahim Kanouche// that are not in the receiver. Returns a copy of the receiver if the argument 130*46c4c49dSIbrahim Kanouche// is nil. 131*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Unique(other *IntSet) *IntSet { 132*46c4c49dSIbrahim Kanouche if other == nil { 133*46c4c49dSIbrahim Kanouche return s.Copy() 134*46c4c49dSIbrahim Kanouche } 135*46c4c49dSIbrahim Kanouche 136*46c4c49dSIbrahim Kanouche sNotInOther := s.Difference(other) 137*46c4c49dSIbrahim Kanouche otherNotInS := other.Difference(s) 138*46c4c49dSIbrahim Kanouche 139*46c4c49dSIbrahim Kanouche // Duplicate Union implementation here to avoid extra Copy, since both 140*46c4c49dSIbrahim Kanouche // sNotInOther and otherNotInS are already copies. 141*46c4c49dSIbrahim Kanouche unique := sNotInOther 142*46c4c49dSIbrahim Kanouche for e := range otherNotInS.set { 143*46c4c49dSIbrahim Kanouche unique.set[e] = present{} 144*46c4c49dSIbrahim Kanouche } 145*46c4c49dSIbrahim Kanouche return unique 146*46c4c49dSIbrahim Kanouche} 147*46c4c49dSIbrahim Kanouche 148*46c4c49dSIbrahim Kanouche// Equal returns true if the receiver and the argument IntSet contain exactly 149*46c4c49dSIbrahim Kanouche// the same elements. Returns false if the argument is nil. 150*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Equal(other *IntSet) bool { 151*46c4c49dSIbrahim Kanouche if s == nil || other == nil { 152*46c4c49dSIbrahim Kanouche return s == nil && other == nil 153*46c4c49dSIbrahim Kanouche } 154*46c4c49dSIbrahim Kanouche 155*46c4c49dSIbrahim Kanouche // Two sets of different length cannot have the exact same unique 156*46c4c49dSIbrahim Kanouche // elements. 157*46c4c49dSIbrahim Kanouche if len(s.set) != len(other.set) { 158*46c4c49dSIbrahim Kanouche return false 159*46c4c49dSIbrahim Kanouche } 160*46c4c49dSIbrahim Kanouche 161*46c4c49dSIbrahim Kanouche // Only one loop is needed. If the two sets are known to be of equal 162*46c4c49dSIbrahim Kanouche // length, then the two sets are equal only if exactly all of the 163*46c4c49dSIbrahim Kanouche // elements in the first set are found in the second. 164*46c4c49dSIbrahim Kanouche for e := range s.set { 165*46c4c49dSIbrahim Kanouche if _, ok := other.set[e]; !ok { 166*46c4c49dSIbrahim Kanouche return false 167*46c4c49dSIbrahim Kanouche } 168*46c4c49dSIbrahim Kanouche } 169*46c4c49dSIbrahim Kanouche 170*46c4c49dSIbrahim Kanouche return true 171*46c4c49dSIbrahim Kanouche} 172*46c4c49dSIbrahim Kanouche 173*46c4c49dSIbrahim Kanouche// Union returns a new IntSet containing the union of the receiver and argument 174*46c4c49dSIbrahim Kanouche// IntSets. Returns a copy of the receiver if the argument is nil. 175*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Union(other *IntSet) *IntSet { 176*46c4c49dSIbrahim Kanouche union := s.Copy() 177*46c4c49dSIbrahim Kanouche if other != nil { 178*46c4c49dSIbrahim Kanouche for e := range other.set { 179*46c4c49dSIbrahim Kanouche union.set[e] = present{} 180*46c4c49dSIbrahim Kanouche } 181*46c4c49dSIbrahim Kanouche } 182*46c4c49dSIbrahim Kanouche return union 183*46c4c49dSIbrahim Kanouche} 184*46c4c49dSIbrahim Kanouche 185*46c4c49dSIbrahim Kanouche// Contains returns true if element is in the IntSet. 186*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Contains(element int) bool { 187*46c4c49dSIbrahim Kanouche _, in := s.set[element] 188*46c4c49dSIbrahim Kanouche return in 189*46c4c49dSIbrahim Kanouche} 190*46c4c49dSIbrahim Kanouche 191*46c4c49dSIbrahim Kanouche// Len returns the number of unique elements in the IntSet. 192*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Len() int { 193*46c4c49dSIbrahim Kanouche return len(s.set) 194*46c4c49dSIbrahim Kanouche} 195*46c4c49dSIbrahim Kanouche 196*46c4c49dSIbrahim Kanouche// Empty returns true if the receiver is the empty set. 197*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Empty() bool { 198*46c4c49dSIbrahim Kanouche return len(s.set) == 0 199*46c4c49dSIbrahim Kanouche} 200*46c4c49dSIbrahim Kanouche 201*46c4c49dSIbrahim Kanouche// Elements returns a []int of the elements in the IntSet, in no particular (or 202*46c4c49dSIbrahim Kanouche// consistent) order. 203*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Elements() []int { 204*46c4c49dSIbrahim Kanouche elements := []int{} // Return at least an empty slice rather than nil. 205*46c4c49dSIbrahim Kanouche for e := range s.set { 206*46c4c49dSIbrahim Kanouche elements = append(elements, e) 207*46c4c49dSIbrahim Kanouche } 208*46c4c49dSIbrahim Kanouche return elements 209*46c4c49dSIbrahim Kanouche} 210*46c4c49dSIbrahim Kanouche 211*46c4c49dSIbrahim Kanouche// Sorted returns a sorted []int of the elements in the IntSet. 212*46c4c49dSIbrahim Kanouchefunc (s *IntSet) Sorted() []int { 213*46c4c49dSIbrahim Kanouche elements := s.Elements() 214*46c4c49dSIbrahim Kanouche sort.Ints(elements) 215*46c4c49dSIbrahim Kanouche return elements 216*46c4c49dSIbrahim Kanouche} 217*46c4c49dSIbrahim Kanouche 218*46c4c49dSIbrahim Kanouche// String formats the IntSet elements as sorted ints, representing them in 219*46c4c49dSIbrahim Kanouche// "array initializer" syntax. 220*46c4c49dSIbrahim Kanouchefunc (s *IntSet) String() string { 221*46c4c49dSIbrahim Kanouche elements := s.Sorted() 222*46c4c49dSIbrahim Kanouche var quoted []string 223*46c4c49dSIbrahim Kanouche for _, e := range elements { 224*46c4c49dSIbrahim Kanouche quoted = append(quoted, fmt.Sprintf("\"%d\"", e)) 225*46c4c49dSIbrahim Kanouche } 226*46c4c49dSIbrahim Kanouche return fmt.Sprintf("{%s}", strings.Join(quoted, ", ")) 227*46c4c49dSIbrahim Kanouche} 228