package tools
type OrderedSet struct {
s []string
m map[string]int
}
func NewOrderedSet() *OrderedSet {
return NewOrderedSetWithCapacity(0)
}
func NewOrderedSetWithCapacity(capacity int) *OrderedSet {
return &OrderedSet{
s: make([]string, 0, capacity),
m: make(map[string]int, capacity),
}
}
func NewOrderedSetFromSlice(s []string) *OrderedSet {
set := NewOrderedSetWithCapacity(len(s))
for _, e := range s {
set.Add(e)
}
return set
}
func (s *OrderedSet) Add(i string) bool {
if _, ok := s.m[i]; ok {
return false
}
s.s = append(s.s, i)
s.m[i] = len(s.s) - 1
return true
}
func (s *OrderedSet) Contains(i string) bool {
if _, ok := s.m[i]; ok {
return true
}
return false
}
func (s *OrderedSet) ContainsAll(i ...string) bool {
for _, item := range i {
if !s.Contains(item) {
return false
}
}
return true
}
func (s *OrderedSet) IsSubset(other *OrderedSet) bool {
for _, i := range other.s {
if !s.Contains(i) {
return false
}
}
return true
}
func (s *OrderedSet) IsSuperset(other *OrderedSet) bool {
return other.IsSubset(s)
}
func (s *OrderedSet) Union(other *OrderedSet) *OrderedSet {
union := NewOrderedSetWithCapacity(other.Cardinality() + s.Cardinality())
for _, e := range s.s {
union.Add(e)
}
for _, e := range other.s {
union.Add(e)
}
return union
}
func (s *OrderedSet) Intersect(other *OrderedSet) *OrderedSet {
intersection := NewOrderedSetWithCapacity(MinInt(
s.Cardinality(), other.Cardinality()))
if s.Cardinality() < other.Cardinality() {
for _, elem := range s.s {
if other.Contains(elem) {
intersection.Add(elem)
}
}
} else {
for _, elem := range other.s {
if s.Contains(elem) {
intersection.Add(elem)
}
}
}
return intersection
}
func (s *OrderedSet) Difference(other *OrderedSet) *OrderedSet {
diff := NewOrderedSetWithCapacity(s.Cardinality())
for _, e := range s.s {
if !other.Contains(e) {
diff.Add(e)
}
}
return diff
}
func (s *OrderedSet) SymmetricDifference(other *OrderedSet) *OrderedSet {
left := s.Difference(other)
right := other.Difference(s)
return left.Union(right)
}
func (s *OrderedSet) Clear() {
s.s = make([]string, 0)
s.m = make(map[string]int, 0)
}
func (s *OrderedSet) Remove(i string) {
idx, ok := s.m[i]
if !ok {
return
}
rest := MinInt(idx+1, len(s.s)-1)
s.s = append(s.s[:idx], s.s[rest:]...)
for _, e := range s.s[rest:] {
s.m[e] = s.m[e] - 1
}
delete(s.m, i)
}
func (s *OrderedSet) Cardinality() int {
return len(s.s)
}
func (s *OrderedSet) Iter() <-chan string {
c := make(chan string)
go func() {
for _, i := range s.s {
c <- i
}
close(c)
}()
return c
}
func (s *OrderedSet) Equal(other *OrderedSet) bool {
if s.Cardinality() != other.Cardinality() {
return false
}
for e, i := range s.m {
if ci, ok := other.m[e]; !ok || ci != i {
return false
}
}
return true
}
func (s *OrderedSet) Clone() *OrderedSet {
clone := NewOrderedSetWithCapacity(s.Cardinality())
for _, i := range s.s {
clone.Add(i)
}
return clone
}