set

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 7 Imported by: 2

README

go-set

A modern, idiomatic and fast set collection for Go.

GitHub Release CI/CD codecov Go Report Card GitHub License Go Reference

Content

Description

go-set is a type-safe set collection for Go 1.23+ with a standard library like API. It's zero value is ready to use - no initialization needed. The implementation is fast and memory efficient.

Features

  • Type Safe: Sets are built with Go generics to provide type safety.
  • Usable Zero-Value: The zero value is ready to use - no initialization needed.
  • Familiar API: The API design is similar to Go's slices package.
  • Top performance: Outperforms or matches other popular set libraries.
  • Standard iterators: First-class support of Go's 1.23+ standard iterators.
  • JSON Support: Built-in marshalling and unmarshaling for JSON.
  • Dependency Free: No external dependencies.
  • Fully tested: Fully tested with 100% coverage.
  • Fully Documented: Full API documentation with many examples.

Please note that go-set is not save to use concurrently, as it prioritizes performance over thread-safety.

Installation

You can add this library to your Go module with the following command:

go get github.com/ErikKalkoken/go-set

Quick Start

The following code example showcases many features of go-set:

package main

import (
    "fmt"
    "github.com/ErikKalkoken/go-set"
)

func main() {
    // Declaring a new set of integers
	var s1 set.Set[int]

	// Basic Operations
	s1.Add(7, 1, 2, 3, 4) // Add multiple elements
	s1.Delete(1)          // Remove an element

	fmt.Println("Set 1:", s1) // {2 3 4 7} (Sorted in output)
	fmt.Printf("Size of s1: %d\n", s1.Size())

	// Membership Checks
	if s1.Contains(3) {
		fmt.Println("Set 1 contains 3")
	}

	// Creating a new set from a list of integers
	s2 := set.Of(3, 4, 5, 6)

	// Set Algebra (Union, Intersection, Difference)
	// Union: All elements from both sets
	u := set.Union(s1, s2)
	fmt.Println("Union:", u) // {2 3 4 5 6 7}

	// Intersection: Only elements present in both sets
	i := set.Intersection(s1, s2)
	fmt.Println("Intersection:", i) // {3 4}

	// Difference: Elements in s1 that are NOT in s2
	d := set.Difference(s1, s2)
	fmt.Println("Difference (s1 - s2):", d) // {2 7}

    // Ranging over set elements
    for v := range s1.All() {
        fmt.Println(v)
    }
}

Performance comparison

We have benchmarked the performance of go-set (goset) and compared it with the two very popular set libraries:

Our measurements show that goset consistently outperforms both golangset and k8ssetsacross nearly every performance metric, demonstrating superior speed and memory efficiency.

[^1]: We used the non-threads safe variant since all the other libraries are also not thread safe.

Approach

The benchmarks measure the performance of common set operations for each of the libraries with with set sizes of 10,000 elements. They were run 10 times to ensure statistically significant data and we used benchstat to compare the results. All benchmarks were performed on a Linux amd64 system with an Intel Core i5-10210U CPU. The detailed results can be found here: go-set-benchmark

Results

The following table shows a summary of the benchmarks results.

Operation Metric golangset k8ssets goset
Membership Time (sec/op) $31.835\text{ ns}$ $8.024\text{ ns}$ $7.670\text{ ns}$
Memory (B/op) $8.00\text{ B}$ $0.00\text{ B}$ $0.00\text{ B}$
Allocs (op) $1.00$ $0.00$ $0.00$
Add Time (sec/op) $267.0\text{ ns}$ $227.4\text{ ns}$ $222.6\text{ ns}$
Memory (B/op) $54.00\text{ B}$ $47.50\text{ B}$ $46.00\text{ B}$
Allocs (op) $0.00$ $0.00$ $0.00$
Remove Time (sec/op) $231.2\text{ ns}$ $197.3\text{ ns}$ $197.9\text{ ns}$
Memory (B/op) $0.00\text{ B}$ $0.00\text{ B}$ $0.00\text{ B}$
Allocs (op) $0.00$ $0.00$ $0.00$
Union Time (sec/op) $1028.5\text{ µs}$ $1045.9\text{ µs}$ $842.6\text{ µs}$
Memory (B/op) $818.1\text{ KiB}$ $818.8\text{ KiB}$ $811.8\text{ KiB}$
Allocs (op) $95.00$ $92.00$ $93.00$
Intersection Time (sec/op) $632.7\text{ µs}$ $634.7\text{ µs}$ $622.4\text{ µs}$
Memory (B/op) $289.2\text{ KiB}$ $289.2\text{ KiB}$ $289.2\text{ KiB}$
Allocs (op) $50.00$ $48.00$ $48.00$
Difference Time (sec/op) $619.3\text{ µs}$ $642.1\text{ µs}$ $620.0\text{ µs}$
Memory (B/op) $289.2\text{ KiB}$ $289.2\text{ KiB}$ $289.2\text{ KiB}$
Allocs (op) $50.00$ $48.00$ $48.00$

Used by

The following projects are using go-set:

  • EVE buddy - EVE Buddy is a companion app for Eve Online players available on Windows, macOS, Linux and Android.

Documentation

For the full API documentation including many examples please see: Go Reference.

Documentation

Overview

Package set provides a generic set type and various related functions.

Using Set in tests

For asserting equality of sets in tests we recommend using Set.Equal as the equality comparison operator does not work and reflect.DeepEqual (e.g. used by assert.Equal) can give wrong results. The below example shows how to assert equality between sets correctly:

  if !got.Equal(want) {
	   t.Errorf("got %q, wanted %q", got, want)
  }

Zero sets

The zero value of a Set or "zero set" is an empty set ready to use. Zero sets are treated the same as empty sets and preserved (e.g. Clone, JSON marshaling).

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	// Declaring a new set of integers
	var s1 set.Set[int]

	// Basic Operations
	s1.Add(7, 1, 2, 3, 4) // Add multiple elements
	s1.Delete(1)          // Remove an element

	fmt.Println("Set 1:", s1) // {2 3 4 7} (Sorted in output)
	fmt.Printf("Size of s1: %d\n", s1.Size())

	// Membership Checks
	if s1.Contains(3) {
		fmt.Println("Set 1 contains 3")
	}

	// Creating a new set from a list of integers
	s2 := set.Of(3, 4, 5, 6)

	// Set Algebra (Union, Intersection, Difference)
	// Union: All elements from both sets
	u := set.Union(s1, s2)
	fmt.Println("Union:", u) // {2 3 4 5 6 7}

	// Intersection: Only elements present in both sets
	i := set.Intersection(s1, s2)
	fmt.Println("Intersection:", i) // {3 4}

	// Difference: Elements in s1 that are NOT in s2
	d := set.Difference(s1, s2)
	fmt.Println("Difference (s1 - s2):", d) // {2 7}

}
Output:
Set 1: {2 3 4 7}
Size of s1: 4
Set 1 contains 3
Union: {2 3 4 5 6 7}
Intersection: {3 4}
Difference (s1 - s2): {2 7}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Max

func Max[E comparableAndOrderable](s Set[E]) E

Max returns the maximal value in s. It panics if s is empty.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(set.Max(s))
}
Output:
2

func MaxFunc

func MaxFunc[E comparable](s Set[E], cmp func(a, b E) int) E

MaxFunc returns the maximal value in s, using cmp to compare elements. It panics if s is empty. If there is more than one maximal element, which one is returned is unspecified.

Example
package main

import (
	"cmp"
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(set.MaxFunc(s, func(a, b int) int {
		return cmp.Compare(a, b)
	}))
}
Output:
2

func Min

func Min[E comparableAndOrderable](s Set[E]) E

Min returns the minimal value in s. It panics if s is empty.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(set.Min(s))
}
Output:
1

func MinFunc

func MinFunc[E comparable](s Set[E], cmp func(a, b E) int) E

MinFunc returns the minimal value in s, using cmp to compare elements. It panics if s is empty. If there is more than one minimal element, which one is returned is unspecified.

Example
package main

import (
	"cmp"
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(set.MinFunc(s, func(a, b int) int {
		return cmp.Compare(a, b)
	}))
}
Output:
1

Types

type Set

type Set[E comparable] struct {
	// contains filtered or unexported fields
}

A Set is an unordered collection of unique elements.

Sets don't need to be initialized as it's zero value is an empty set ready to use. The equality comparison operator (==) does not work for Sets. Instead Set.Equal should be used to compare sets. Set is not safe for concurrent use.

func Collect

func Collect[E comparable](seq iter.Seq[E]) Set[E]

Collect collects values from seq into a new set and returns it. If seq is empty, the result is a zero set.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Collect(set.Of(1, 2, 3).All())
	fmt.Println(s)
}
Output:
{1 2 3}

func Difference

func Difference[E comparable](s Set[E], others ...Set[E]) Set[E]

Difference constructs a new Set containing the elements of s that are not present in the union of others. When no others are provided it returns a set with the elements of s.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s1 := set.Of(1, 2)
	s2 := set.Of(2, 3)
	fmt.Println(set.Difference(s1, s2))
}
Output:
{1}

func Intersection

func Intersection[E comparable](sets ...Set[E]) Set[E]

Intersection returns a new Set with elements common to all sets. When less then two sets are provided it returns an empty set.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s1 := set.Of(1, 2)
	s2 := set.Of(2, 3)
	fmt.Println(set.Intersection(s1, s2))
}
Output:
{2}

func Of

func Of[E comparable](v ...E) Set[E]

Of returns a new set of the elements v. Providing no elements will return an empty and initialized set.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s1 := set.Of(1, 2, 2)
	s2 := set.Of([]int{3, 4}...)
	s3 := set.Of[int]()
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(s3)
}
Output:
{1 2}
{3 4}
{}

func Union

func Union[E comparable](sets ...Set[E]) Set[E]

Union returns a new Set with has the combined elements of all provided sets. When no sets are provided it returns an empty set.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s1 := set.Of(1, 2)
	s2 := set.Of(2, 3)
	fmt.Println(set.Union(s1, s2))
}
Output:
{1 2 3}

func (*Set[E]) Add

func (s *Set[E]) Add(v ...E)

Add adds elements v to set s.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	var s set.Set[int]
	s.Add(1, 2)
	fmt.Println(s)
}
Output:
{1 2}

func (*Set[E]) AddSeq

func (s *Set[E]) AddSeq(seq iter.Seq[E])

AddSeq adds the values from seq to s.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	s.AddSeq(slices.Values([]int{3, 4}))
	fmt.Println(s)
}
Output:
{1 2 3 4}

func (Set[E]) All

func (s Set[E]) All() iter.Seq[E]

All returns on iterator over all elements of set s.

Note that the order of the elements is undefined.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2, 3)
	for x := range s.All() {
		fmt.Println(x)
	}
}
Output:
1
2
3

func (Set[E]) Clear

func (s Set[E]) Clear()

Clear removes all elements from set s.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	s.Clear()
	fmt.Println(s)
}
Output:
{}

func (Set[E]) Clone

func (s Set[E]) Clone() Set[E]

Clone returns a new set, which contains a shallow copy of all elements of set s. Zero sets are preserved.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s1 := set.Of(1, 2)
	s2 := s1.Clone()
	fmt.Println(s2)
}
Output:
{1 2}

func (Set[E]) Contains

func (s Set[E]) Contains(v E) bool

Contains reports whether element v is in set s.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(s.Contains(2))
	fmt.Println(s.Contains(3))
}
Output:
true
false

func (Set[E]) ContainsAll

func (s Set[E]) ContainsAll(seq iter.Seq[E]) bool

ContainsAll reports whether all of the elements in seq are in s.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(s.ContainsAll(set.Of(1).All()))
	fmt.Println(s.ContainsAll(set.Of(1, 2).All()))
	fmt.Println(s.ContainsAll(set.Of(1, 2, 3).All()))
}
Output:
true
true
false

func (Set[E]) ContainsAny

func (s Set[E]) ContainsAny(seq iter.Seq[E]) bool

ContainsAny reports whether any of the elements in seq are in s.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(s.ContainsAny(set.Of(1).All()))
	fmt.Println(s.ContainsAny(set.Of(1, 2).All()))
	fmt.Println(s.ContainsAny(set.Of(1, 2, 3).All()))
	fmt.Println(s.ContainsAny(set.Of(1, 3).All()))
	fmt.Println(s.ContainsAny(set.Of(3, 4).All()))
}
Output:
true
true
true
true
false

func (Set[E]) ContainsFunc

func (s Set[E]) ContainsFunc(f func(E) bool) bool

ContainsFunc reports whether at least one element v of s satisfies f(v).

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(s.ContainsFunc(func(x int) bool {
		return x == 2
	}))
	fmt.Println(s.ContainsFunc(func(x int) bool {
		return x == 3
	}))
}
Output:
true
false

func (Set[E]) Delete

func (s Set[E]) Delete(v ...E) int

Delete removes elements v from set s. It returns the number of deleted elements. Elements that are not found in the set are ignored.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	s.Delete(2)
	fmt.Println(s)
}
Output:
{1}

func (Set[E]) DeleteFunc

func (s Set[E]) DeleteFunc(del func(E) bool) int

DeleteFunc deletes the elements in s for which del returns true. It returns the number of deleted elements.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	s.DeleteFunc(func(x int) bool {
		return x == 2
	})
	fmt.Println(s)
}
Output:
{1}

func (Set[E]) DeleteSeq

func (s Set[E]) DeleteSeq(seq iter.Seq[E]) int

DeleteSeq deletes the elements in seq from s. Elements that are not present are ignored. It returns the number of deleted elements.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2, 3)
	s.DeleteSeq(set.Of(2, 3, 4).All())
	fmt.Println(s)
}
Output:
{1}

func (Set[E]) Equal

func (s Set[E]) Equal(u Set[E]) bool

Equal reports whether sets s and u are equal. A zero set will be reported equal to an (initialized) empty set.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2)
	fmt.Println(s.Equal(set.Of(1, 2)))
	fmt.Println(s.Equal(set.Of(1, 3)))
}
Output:
true
false

func (Set[E]) IsZero added in v0.2.0

func (s Set[E]) IsZero() bool

IsZero reports whether set s is a zero value.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	var s1 set.Set[int]
	s2 := set.Of[int]()
	fmt.Println(s1.IsZero())
	fmt.Println(s2.IsZero())
}
Output:
true
false

func (Set[T]) MarshalJSON

func (s Set[T]) MarshalJSON() ([]byte, error)

MarshalJSON returns the JSON encoding of the set. Sets are converted to JSON arrays. Zero sets will be converted into JSON null.

func (Set[E]) Pop

func (s Set[E]) Pop() (E, bool)

Pop tries to remove and return an arbitrary element from s and reports whether it was successful.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1)
	v, ok := s.Pop()
	fmt.Println(v, ok)
	_, ok = s.Pop()
	fmt.Println(ok)
}
Output:
1 true
false

func (Set[E]) Size

func (s Set[E]) Size() int

Size returns the number of elements in set s. An empty set returns 0.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2, 3)
	fmt.Println(s.Size())
}
Output:
3

func (Set[E]) String

func (s Set[E]) String() string

String returns a string representation of set s. Sets are printed with curly brackets and sorted, e.g. {1 2}.

Example
package main

import (
	"fmt"

	"github.com/ErikKalkoken/go-set"
)

func main() {
	s := set.Of(1, 2, 3)
	fmt.Println(s)
}
Output:
{1 2 3}

func (*Set[T]) UnmarshalJSON

func (s *Set[T]) UnmarshalJSON(b []byte) error

UnmarshalJSON parses the JSON-encoded data b and replaces the current set. JSON null values will be unmarshaled into a zero set.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL