In programming languages like go, there is no built-in type for set. A set essentially answers yes or no: is a given element present?
We can use the built-in map type to implement sets.
I used to implement map-as-set like this:
// assuming the element type in the set is string
set := map[string]bool{
"apple": true,
"banana": true,
"cherry": true,
}
given := "banana"
// is "banana" in the set?
if set[given] {
// "banana" is in the set
}
Apparently, Gemini thinks there’s a better way:
// assuming the element type in the set is string
set := map[string]struct{}{
"apple": struct{}{},
"banana": struct{}{},
"cherry": struct{}{},
}
given := "banana"
// is "banana" in the set?
if _, ok := set[given]; ok {
// "banana" is in the set
}
Gemini thinks this is better because it saves memory. a bool value takes 1 byte, but an empty object struct{}{} takes 0 bytes; however, we can no longer assess the return value in a boolean manner, because it doesn’t matter whether the key is present or not present; the first return value will always be an empty object struct{}{} which is ambiguous af; therefore, an explicit check on the 2nd return value (i.e. ok in this case) is necessary.
Let’s implement a full-blown custom Set type.
type Set[T comparable] struct {
kv map[T]struct{}
}
func NewSet[T comparable]() *Set[T] {
return &Set[T]{
kv: make(map[T]struct{}),
}
}
func (s *Set[T]) Add(element T) {
s.kv[element] = struct{}{}
}
func (s *Set[T]) Remove(element T) {
delete(s.kv, element)
}
func (s *Set[T]) Contains(element T) bool {
_, found := s.kv[element]
return found
}
func (s *Set[T]) Len() int {
return len(s.kv)
}
func (s *Set[T]) Clear() {
clear(s.kv)
}
Ok bye.