github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/sets/hashset/hashset.go (about)

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