Go

How do you implement a set in Go, and what maps package helpers exist?

Question 71MediumGo 1.22 to 1.25

Go has no built-in set type. The idiom is map[T]struct{}. The empty struct takes zero bytes, so values cost nothing, and the type makes the intent clear. map[T]bool uses 1 byte per entry and allows if set[x], but it also allows an ambiguous false value.

type Set[T comparable] map[T]struct{}

func Of[T comparable](items ...T) Set[T] {
	s := make(Set[T], len(items))
	for _, v := range items {
		s[v] = struct{}{}
	}
	return s
}

func (s Set[T]) Has(v T) bool { _, ok := s[v]; return ok }
func (s Set[T]) Add(v T)      { s[v] = struct{}{} }

func (s Set[T]) Intersect(o Set[T]) Set[T] {
	small, big := s, o
	if len(big) < len(small) {
		small, big = big, small // iterate the smaller set
	}
	out := Set[T]{}
	for k := range small {
		if big.Has(k) {
			out.Add(k)
		}
	}
	return out
}

// Sorted, deterministic listing
func (s Set[T]) Sorted(less func(a, b T) int) []T {
	return slices.SortedFunc(maps.Keys(s), less)
}

maps package helpers:

  • maps.Clone makes a shallow copy and keeps nil as nil.
  • maps.Copy(dst, src) overwrites any keys that already exist in dst.
  • maps.Equal and maps.EqualFunc compare maps.
  • maps.DeleteFunc deletes the entries that match a predicate.
  • Since Go 1.23 there are also maps.Keys, maps.Values and maps.All (iterators), and maps.Collect and maps.Insert.

Gotcha: maps.Clone is shallow. Slice or map values inside it are still shared.

More on Arrays, Slices, Maps & Strings

All 37 Arrays, Slices, Maps & Strings questions