sets

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2025 License: MIT Imports: 5 Imported by: 0

README

sets GoDoc Go Report Card

A minimal, Python-like set utility for Go.

✨ Features

  • ✅ Type-safe and generic set based on Go's map
  • ✅ Constant-time: Add, Remove, Contains, Len, Clear
  • ✅ Supports union, intersection, difference, symmetric difference
  • ✅ Provides iterators and JSON (un)marshaling
  • ❌ Not concurrency-safe
  • ❌ Only for comparable types

🧱 Example

package main

import (
	"fmt"
	"github.com/byExist/sets"
)

func main() {
	// Create a new set
	s := sets.New[int]()
	
	// Add elements to the set
	sets.Add(s, 1)
	sets.Add(s, 2)
	sets.Add(s, 3)

	// Iterate over set elements in sorted order
	elems := slices.Collect(sets.Values(s))
	slices.Sort(elems)
	for _, e := range elems {
		fmt.Println(e)
	}

	// Check for membership
	fmt.Println("Contains 2?", sets.Contains(s, 2))

	// Remove an element
	sets.Remove(s, 2)

	// Set operations
	t := sets.New[int]()
	sets.Add(t, 3)
	sets.Add(t, 4)

	union := sets.Union(s, t)
	unionElems := slices.Collect(sets.Values(union))
	slices.Sort(unionElems)
	for _, e := range unionElems {
		fmt.Println("Union element:", e)
	}
}

🔍 API

Function/Method Description
New() Create a new empty set
Add(set, elem) Add an element
Remove(set, elem) Remove an element
Contains(set, elem) Check membership
Len(set) Number of elements
Clear(set) Remove all elements
Values(set) Get iterator
Union(a, b) Union of two sets
Intersection(a, b) Intersection of two sets
Difference(a, b) Difference of two sets
SymmetricDifference(a, b) Symmetric difference
Equal(a, b) Check equality
IsSubset(a, b) Check subset
IsSuperset(a, b) Check superset
IsDisjoint(a, b) Check disjointness
Clone(set) Copy set

⚠️ Limitations

  • Not safe for concurrent access
    Use a sync.Mutex if multiple goroutines will access the set.
  • Only works with types that are comparable in Go
    (e.g., slices and maps cannot be used as set elements)

🪪 License

This project is licensed under the MIT License. See the LICENSE file for details.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Add

func Add[E comparable](s Set[E], e E)

Add inserts an element into the set.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	elems := slices.Collect(sets.Values(s))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1 2]

func Clear

func Clear[E comparable](s Set[E])

Clear removes all elements from the set.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	fmt.Println("Before Clear:", sets.Len(s))
	sets.Clear(s)
	fmt.Println("After Clear:", sets.Len(s))
}
Output:

Before Clear: 2
After Clear: 0

func Contains

func Contains[E comparable](s Set[E], e E) bool

Contains checks if the set contains the given element.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	fmt.Println(sets.Contains(s, 1))
	fmt.Println(sets.Contains(s, 2))

}
Output:

true
false

func Equal

func Equal[E comparable](a, b Set[E]) bool

Equal checks if two sets contain exactly the same elements.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s1, 1)
	sets.Add(s2, 1)
	fmt.Println(sets.Equal(s1, s2))

	sets.Add(s2, 2)
	fmt.Println(sets.Equal(s1, s2))

}
Output:

true
false

func IsDisjoint

func IsDisjoint[E comparable](a, b Set[E]) bool

IsDisjoint checks if two sets have no elements in common.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s1, 1)
	sets.Add(s2, 2)
	fmt.Println("s1 and s2 disjoint?", sets.IsDisjoint(s1, s2))

	sets.Add(s2, 1)
	fmt.Println("s1 and s2 disjoint after sharing element?", sets.IsDisjoint(s1, s2))
}
Output:

s1 and s2 disjoint? true
s1 and s2 disjoint after sharing element? false

func IsSubset

func IsSubset[E comparable](a, b Set[E]) bool

IsSubset checks if the first set is a subset of the second set.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s2, 1)
	sets.Add(s2, 2)
	fmt.Println("s1 ⊆ s2?", sets.IsSubset(s1, s2))

	sets.Add(s1, 1)
	fmt.Println("s1 ⊆ s2 after adding 1?", sets.IsSubset(s1, s2))

	sets.Add(s1, 3)
	fmt.Println("s1 ⊆ s2 after adding 3?", sets.IsSubset(s1, s2))
}
Output:

s1 ⊆ s2? true
s1 ⊆ s2 after adding 1? true
s1 ⊆ s2 after adding 3? false

func IsSuperset

func IsSuperset[E comparable](a, b Set[E]) bool

IsSuperset checks if the first set is a superset of the second set.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s1, 1)
	sets.Add(s1, 2)
	fmt.Println("s1 ⊇ s2?", sets.IsSuperset(s1, s2))

	sets.Add(s2, 1)
	fmt.Println("s1 ⊇ s2 after s2 has 1?", sets.IsSuperset(s1, s2))

	sets.Add(s2, 3)
	fmt.Println("s1 ⊇ s2 after s2 has 3?", sets.IsSuperset(s1, s2))
}
Output:

s1 ⊇ s2? true
s1 ⊇ s2 after s2 has 1? true
s1 ⊇ s2 after s2 has 3? false

func Len

func Len[E comparable](s Set[E]) int

Len returns the number of elements in the set.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	fmt.Println(sets.Len(s))

}
Output:

2

func Pop

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

Pop removes and returns an arbitrary element from the set.

Example
package main

import (
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	v, ok := sets.Pop(s)
	fmt.Println("Popped:", v, ok)
	fmt.Println("Len after pop:", sets.Len(s))
}
Output:

Popped: 1 true
Len after pop: 1

func Remove

func Remove[E comparable](s Set[E], e E)

Remove deletes an element from the set.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	sets.Remove(s, 1)
	elems := slices.Collect(sets.Values(s))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[2]

func Values

func Values[E comparable](s Set[E]) iter.Seq[E]

Values returns an iterator over all elements in the set.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	elems := slices.Collect(sets.Values(s))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1 2]

Types

type Set

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

Set represents a generic Set of comparable elements.

func Clone

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

Clone returns a deep copy of the given set.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)

	clone := sets.Clone(s)
	elems := slices.Collect(sets.Values(clone))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1 2]

func Collect

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

Collect creates a set from an iterator sequence.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	input := []int{1, 2, 3, 4}
	s := sets.Collect(slices.Values(input))
	elems := slices.Collect(sets.Values(s))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1 2 3 4]

func Difference

func Difference[E comparable](a, b Set[E]) Set[E]

Difference (A − B): returns a new set containing elements in the first set but not in the second.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s1, 1)
	sets.Add(s1, 2)
	sets.Add(s2, 2)
	sets.Add(s2, 3)
	difference := sets.Difference(s1, s2)
	elems := slices.Collect(sets.Values(difference))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1]

func Intersection

func Intersection[E comparable](a, b Set[E]) Set[E]

Intersection (A ∩ B): returns a new set containing only elements present in both sets.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s1, 1)
	sets.Add(s1, 2)
	sets.Add(s2, 2)
	sets.Add(s2, 3)
	intersection := sets.Intersection(s1, s2)
	elems := slices.Collect(sets.Values(intersection))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[2]

func New

func New[E comparable]() Set[E]

New creates and returns a new empty set.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	sets.Add(s, 3)
	elems := slices.Collect(sets.Values(s))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1 2 3]

func SymmetricDifference

func SymmetricDifference[E comparable](a, b Set[E]) Set[E]

SymmetricDifference (A △ B): returns a new set containing elements present in either set but not in both.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s1, 1)
	sets.Add(s1, 2)
	sets.Add(s2, 2)
	sets.Add(s2, 3)
	symDiff := sets.SymmetricDifference(s1, s2)
	elems := slices.Collect(sets.Values(symDiff))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1 3]

func Union

func Union[E comparable](a, b Set[E]) Set[E]

Union (A ∪ B): returns a new set containing all elements from both sets.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	s1 := sets.New[int]()
	s2 := sets.New[int]()
	sets.Add(s1, 1)
	sets.Add(s2, 2)
	union := sets.Union(s1, s2)
	elems := slices.Collect(sets.Values(union))
	slices.Sort(elems)
	fmt.Println(elems)

}
Output:

[1 2]

func (*Set[E]) MarshalJSON added in v0.1.0

func (s *Set[E]) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for Set[E].

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 1)
	sets.Add(s, 2)
	data, _ := json.Marshal(&s)
	fmt.Println(string(data))
}
Output:

[1,2]

func (Set[E]) String added in v0.1.0

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

String implements fmt.Stringer for Set[E].

Example
package main

import (
	"fmt"
	"slices"
	"strconv"
	"strings"

	"github.com/byExist/sets"
)

func main() {
	s := sets.New[int]()
	sets.Add(s, 3)
	sets.Add(s, 1)
	sets.Add(s, 2)

	str := s.String()
	trimmed := strings.TrimSuffix(strings.TrimPrefix(str, "Set{"), "}")
	parts := strings.Split(trimmed, ", ")

	var nums []int
	for _, p := range parts {
		n, _ := strconv.Atoi(p)
		nums = append(nums, n)
	}

	slices.Sort(nums)
	fmt.Println(nums)

}
Output:

[1 2 3]

func (*Set[E]) UnmarshalJSON added in v0.1.0

func (s *Set[E]) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler for Set[E].

Example
package main

import (
	"encoding/json"
	"fmt"
	"slices"

	"github.com/byExist/sets"
)

func main() {
	var s sets.Set[int]
	err := json.Unmarshal([]byte(`[1,2,3]`), &s)
	if err != nil {
		panic(err)
	}
	elems := slices.Collect(sets.Values(s))
	slices.Sort(elems)
	fmt.Println(elems)
}
Output:

[1 2 3]

Jump to

Keyboard shortcuts

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