github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/collection/set/generic.go (about)

     1  package set
     2  
     3  import "encoding/json"
     4  
     5  // Generic is a generic set collection.
     6  // The zero value of Generic is an empty instance ready to use.
     7  // A zero Generic set value shall not be copied, or it may result
     8  // incorrect behavior.
     9  type Generic[T comparable] struct {
    10  	m map[T]struct{}
    11  }
    12  
    13  // New creates a set instance and add the given values into the set.
    14  func New[T comparable](vals ...T) Generic[T] {
    15  	size := max(len(vals), minSize)
    16  	set := Generic[T]{
    17  		m: make(map[T]struct{}, size),
    18  	}
    19  	for _, v := range vals {
    20  		set.m[v] = struct{}{}
    21  	}
    22  	return set
    23  }
    24  
    25  // NewWithSize creates a set instance with given initial size.
    26  func NewWithSize[T comparable](size int) Generic[T] {
    27  	set := Generic[T]{
    28  		m: make(map[T]struct{}, size),
    29  	}
    30  	return set
    31  }
    32  
    33  // Size returns the size of the set collection.
    34  func (s Generic[T]) Size() int { return len(s.m) }
    35  
    36  // Add adds the given values into the set.
    37  func (s *Generic[T]) Add(vals ...T) {
    38  	if s.m == nil {
    39  		size := max(len(vals), minSize)
    40  		s.m = make(map[T]struct{}, size)
    41  	}
    42  	for _, v := range vals {
    43  		s.m[v] = struct{}{}
    44  	}
    45  }
    46  
    47  // Delete deletes values from the set.
    48  func (s *Generic[T]) Delete(vals ...T) {
    49  	for _, v := range vals {
    50  		delete(s.m, v)
    51  	}
    52  }
    53  
    54  // Iterate iterates the set in no particular order and calls the given
    55  // function for each set element.
    56  func (s Generic[T]) Iterate(fn func(T)) {
    57  	for val := range s.m {
    58  		fn(val)
    59  	}
    60  }
    61  
    62  // Contains returns true if the set contains all the values.
    63  func (s Generic[T]) Contains(vals ...T) bool {
    64  	if len(vals) == 0 {
    65  		return false
    66  	}
    67  	for _, v := range vals {
    68  		if _, ok := s.m[v]; !ok {
    69  			return false
    70  		}
    71  	}
    72  	return true
    73  }
    74  
    75  // ContainsAny returns true if the set contains any of the values.
    76  func (s Generic[T]) ContainsAny(vals ...T) bool {
    77  	for _, v := range vals {
    78  		if _, ok := s.m[v]; ok {
    79  			return true
    80  		}
    81  	}
    82  	return false
    83  }
    84  
    85  // Diff returns a new set about the values which other set doesn't contain.
    86  func (s Generic[T]) Diff(other Generic[T]) Generic[T] {
    87  	res := NewWithSize[T](s.Size())
    88  
    89  	for val := range s.m {
    90  		if _, ok := other.m[val]; !ok {
    91  			res.m[val] = struct{}{}
    92  		}
    93  	}
    94  	return res
    95  }
    96  
    97  // DiffSlice is similar to Diff, but takes a slice as parameter.
    98  func (s Generic[T]) DiffSlice(other []T) Generic[T] {
    99  	otherLen := len(other)
   100  	if len(s.m) > otherLen {
   101  		tmp := NewWithSize[T](otherLen)
   102  		dup := 0
   103  		for i := 0; i < otherLen; i++ {
   104  			val := other[i]
   105  			if _, ok := s.m[val]; ok {
   106  				dup++
   107  			}
   108  			tmp.m[val] = struct{}{}
   109  		}
   110  		res := NewWithSize[T](max(s.Size()-dup, 0))
   111  		for val := range s.m {
   112  			if _, ok := tmp.m[val]; !ok {
   113  				res.m[val] = struct{}{}
   114  			}
   115  		}
   116  		return res
   117  	}
   118  
   119  	res := NewWithSize[T](s.Size())
   120  	for val := range s.m {
   121  		res.m[val] = struct{}{}
   122  	}
   123  	for i := 0; i < otherLen; i++ {
   124  		val := other[i]
   125  		delete(res.m, val)
   126  	}
   127  	return res
   128  }
   129  
   130  // FilterContains returns a new slice which contains values that present
   131  // in the provided slice and also present in the set.
   132  func (s Generic[T]) FilterContains(slice []T) []T {
   133  	res := make([]T, 0, min(s.Size(), len(slice)))
   134  	for _, val := range slice {
   135  		if _, ok := s.m[val]; ok {
   136  			res = append(res, val)
   137  		}
   138  	}
   139  	return res
   140  }
   141  
   142  // FilterNotContains returns a new slice which contains values that present
   143  // in the provided slice but don't present in the set.
   144  func (s Generic[T]) FilterNotContains(slice []T) []T {
   145  	res := make([]T, 0, len(slice))
   146  	for _, val := range slice {
   147  		if _, ok := s.m[val]; !ok {
   148  			res = append(res, val)
   149  		}
   150  	}
   151  	return res
   152  }
   153  
   154  // Intersect returns a new set about values which other set also contains.
   155  func (s Generic[T]) Intersect(other Generic[T]) Generic[T] {
   156  	res := NewWithSize[T](min(s.Size(), other.Size()))
   157  
   158  	// loop over the smaller set for better performance
   159  	small, big := s, other
   160  	if s.Size() > other.Size() {
   161  		small, big = other, s
   162  	}
   163  	for val := range small.m {
   164  		if _, ok := big.m[val]; ok {
   165  			res.m[val] = struct{}{}
   166  		}
   167  	}
   168  	return res
   169  }
   170  
   171  // IntersectSlice is similar to Intersect, but takes a slice as parameter.
   172  func (s Generic[T]) IntersectSlice(other []T) Generic[T] {
   173  	res := NewWithSize[T](min(s.Size(), len(other)))
   174  	for _, val := range other {
   175  		if _, ok := s.m[val]; ok {
   176  			res.m[val] = struct{}{}
   177  		}
   178  	}
   179  	return res
   180  }
   181  
   182  // Union returns a new set about values either in the set or the other set.
   183  func (s Generic[T]) Union(other Generic[T]) Generic[T] {
   184  	res := NewWithSize[T](s.Size() + other.Size())
   185  	for val := range s.m {
   186  		res.m[val] = struct{}{}
   187  	}
   188  	for val := range other.m {
   189  		res.m[val] = struct{}{}
   190  	}
   191  	return res
   192  }
   193  
   194  // UnionSlice is similar to Union, but takes a slice as parameter.
   195  func (s Generic[T]) UnionSlice(other []T) Generic[T] {
   196  	res := NewWithSize[T](s.Size() + len(other))
   197  	for val := range s.m {
   198  		res.m[val] = struct{}{}
   199  	}
   200  	for _, val := range other {
   201  		res.m[val] = struct{}{}
   202  	}
   203  	return res
   204  }
   205  
   206  // Slice converts the set into a slice of type []T.
   207  func (s Generic[T]) Slice() []T {
   208  	res := make([]T, 0, len(s.m))
   209  	for val := range s.m {
   210  		res = append(res, val)
   211  	}
   212  	return res
   213  }
   214  
   215  // Map converts the set into a map of type map[T]bool.
   216  func (s Generic[T]) Map() map[T]bool {
   217  	res := make(map[T]bool, len(s.m))
   218  	for val := range s.m {
   219  		res[val] = true
   220  	}
   221  	return res
   222  }
   223  
   224  // MarshalJSON implements json.Marshaler interface, the set will be
   225  // marshaled as a slice []T.
   226  func (s Generic[T]) MarshalJSON() ([]byte, error) {
   227  	res := s.Slice()
   228  	return json.Marshal(res)
   229  }
   230  
   231  // UnmarshalJSON implements json.Unmarshaler interface, it will unmarshal
   232  // a slice []T to the set.
   233  func (s *Generic[T]) UnmarshalJSON(b []byte) error {
   234  	vals := make([]T, 0)
   235  	err := json.Unmarshal(b, &vals)
   236  	if err == nil {
   237  		s.Add(vals...)
   238  	}
   239  	return err
   240  }
   241  
   242  // MarshalYAML implements yaml.Marshaler interface of the yaml package,
   243  // the set will be marshaled as a slice []T.
   244  func (s Generic[T]) MarshalYAML() (any, error) {
   245  	res := s.Slice()
   246  	return res, nil
   247  }
   248  
   249  // UnmarshalYAML implements yaml.Unmarshaler interface of the yaml package,
   250  // it will unmarshal a slice []T to the set.
   251  func (s *Generic[T]) UnmarshalYAML(unmarshal func(any) error) error {
   252  	vals := make([]T, 0)
   253  	err := unmarshal(&vals)
   254  	if err == nil {
   255  		s.Add(vals...)
   256  	}
   257  	return err
   258  }