slices2

package module
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MIT Imports: 3 Imported by: 0

README

slices2 GoDoc Build Status Go Report Card

Useful generic tools for Go slices.

Released under the MIT License.

See package documentation.

Documentation

Overview

Package slices2 contains slice related helpers missing in standard "slices" package.

To avoid conflicts with standard "slices" package the package named as slices2:

import (
	"github.com/Pilatuz/slices2"
)

Some helpers able to do "in-place" work, i.e. there is no memory allocation for result. Such functions usually have "InPlace" suffix in their names.

Filtering and Rejecting

Filter and Reject are very similar but use inversed condition.

  • Filter removes elements that DO NOT PASS condition
  • Reject removes elements that DO PASS condition

Both have options to modify input slice "in-place" (without memory allocation).

Uniqueness

Unique and UniqueBy remove duplicates from a slice. Unlike standard slices.Compact, they work with unsorted input. Also available "InPlace" versions for memory-efficient operations.

Set Operations

The package provides functions for set operations:

  • SetAnd — intersection (elements present in both slices)
  • SetOr — union (unique elements from both slices)
  • SetSub — difference (elements in s1 missing in s2)
  • SetDiff — symmetric difference (elements present in only one of the slices)

All set operation functions have "By" variants for custom key extraction.

Sorting and Reversing

SortInPlace and SortFuncInPlace sort a slice in ascending order. Sorted and SortedFunc return a new sorted slice. Reversed returns a new slice with elements in reverse order. ReverseInPlace reverses elements of a slice in place.

Transformation

Transform transforms each element of a slice from one type to another. TransformEx transforms elements with error handling. Special error ErrSkip allows skipping elements. Deref dereferences pointers, skipping nil values.

Grouping

GroupBy groups slice elements by a key.

Joining Slices

Join joins multiple slices into one.

Cloning

Clone makes a copy of a slice.

Set Type

Type Set represents a set of unique elements based on map[K]struct{}. Methods:

  • Push — add elements
  • Pop — remove elements
  • Has — check if element exists
  • HasAll — check if all elements exist
  • HasAny — check if any element exists
  • All — get all elements as a slice

Go Versions

The package supports Go 1.21+ and earlier versions. For Go 1.21+ it uses standard functions slices.Clone, slices.Reverse, slices.Sort.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrSkip = errors.New("skip")

ErrSkip is a special sentinel error that indicates the current element should be skipped. Used in transformation functions with error handling.

Functions

func Clone

func Clone[S ~[]E, E any](s S) S

Clone makes a copy of a slice. Returns nil for nil slice.

func Deref added in v0.0.5

func Deref[T any](p *T) (T, error)

Deref dereferences pointers to values. Nil pointers are skipped with ErrSkip error.

func Filter

func Filter[S ~[]E, E any](s S, condFn func(E) bool) S

Filter removes elements that DO NOT PASS condition. Returns new slice with elements that pass the condition.

The condFn function returns true for elements that should be kept.

Example

ExampleFilter an example for `Filter` function.

package main

import (
	"fmt"
	"unicode/utf8"

	"github.com/Pilatuz/slices2"
)

func main() {
	ss := []string{"foo", "barbaz"}
	cond := func(s string) bool {
		return utf8.RuneCountInString(s) > 3
	}
	fmt.Println(slices2.Filter(ss, cond))
}
Output:
[barbaz]

func FilterInPlace

func FilterInPlace[S ~[]E, E any](s S, condFn func(E) bool) S

FilterInPlace removes elements that DO NOT PASS condition. Returns original slice with elements removed in-place (no memory allocation).

The condFn function returns true for elements that should be kept.

func FromChannel

func FromChannel[E any](ch <-chan E) []E

FromChannel drains the channel ch into a slice.

It collects ALL the values from channel ch until the channel is closed.

Example

ExampleFromChannel an example for `FromChannel` function.

package main

import (
	"fmt"
	"sync"

	"github.com/Pilatuz/slices2"
)

func main() {
	wg := &sync.WaitGroup{}
	errCh := make(chan error)

	wg.Add(3)
	go func() {
		defer wg.Done()
		errCh <- nil
	}()
	go func() {
		defer wg.Done()
		errCh <- nil
	}()
	go func() {
		defer wg.Done()
		errCh <- nil
	}()

	go func() {
		wg.Wait()
		close(errCh)
	}()

	res := slices2.FromChannel(errCh)
	fmt.Println(res)
}
Output:
[<nil> <nil> <nil>]

func GroupBy added in v0.0.3

func GroupBy[S ~[]E, E any, K comparable](s S, byFn func(E) K) map[K]S

GroupBy groups slice elements by a key. Returns a map where keys are results of byFn function and values are slices of elements with that key.

Example

ExampleGroupBy an example for `GroupBy` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	words := []string{"apple", "apricot", "banana", "blueberry"}
	grouped := slices2.GroupBy(words, func(s string) string { return s[:1] })
	fmt.Println(grouped["a"])
	fmt.Println(grouped["b"])
}
Output:
[apple apricot]
[banana blueberry]

func Join

func Join[S ~[]E, E any](ss ...S) S

Join joins multiple slices into one. Returns a new slice containing elements from all input slices.

Example

ExampleJoin an example for `Join` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	s := slices2.Join(
		[]string{"foo", "bar"},
		[]string{"baz"})
	fmt.Println(s)
}
Output:
[foo bar baz]

func Reject

func Reject[S ~[]E, E any](s S, condFn func(E) bool) S

Reject removes elements that DO PASS condition. Returns new slice with elements that do NOT pass the condition.

The condFn function returns true for elements that should be removed.

Example

ExampleReject an example for `Reject` function.

package main

import (
	"fmt"
	"unicode/utf8"

	"github.com/Pilatuz/slices2"
)

func main() {
	ss := []string{"foo", "barbaz"}
	cond := func(s string) bool {
		return utf8.RuneCountInString(s) > 3
	}
	fmt.Println(slices2.Reject(ss, cond))
}
Output:
[foo]

func RejectInPlace

func RejectInPlace[S ~[]E, E any](s S, condFn func(E) bool) S

RejectInPlace removes elements that DO PASS condition. Returns original slice with elements removed in-place (no memory allocation).

The condFn function returns true for elements that should be removed.

func ReverseInPlace added in v0.0.3

func ReverseInPlace[S ~[]E, E any](s S)

ReverseInPlace reverses elements of a slice (in place).

func Reversed added in v0.0.3

func Reversed[S ~[]E, E any](s S) S

Reversed returns a new slice with elements in reverse order. As opposite to ReverseInPlace, this function always allocates a new array.

Example

ExampleReversed an example for `Reversed` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	s := []int{1, 2, 3}
	r := slices2.Reversed(s)
	fmt.Println(s)
	fmt.Println(r)
}
Output:
[1 2 3]
[3 2 1]

func SetAnd

func SetAnd[S ~[]E, E comparable](s1 S, s2 S) S

SetAnd returns the intersection between two sets. I.e. elements presented in both slices. Order is preserved from s2.

Example

ExampleSetAnd an example for `SetAnd` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	a := []string{"foo", "bar"}
	b := []string{"bar", "baz"}

	c := slices2.SetAnd(a, b)
	fmt.Println(a, "&", b, "=", c)
}
Output:
[foo bar] & [bar baz] = [bar]

func SetAndBy

func SetAndBy[S ~[]E, E any, K comparable](s1 S, s2 S, byFn func(E) K) S

SetAndBy returns the intersection between two sets by custom key. I.e. elements presented in both slices. The byFn function extracts a comparison key from each element. Order is preserved from s2.

func SetDiff

func SetDiff[S ~[]E, E comparable](s1 S, s2 S) (out1 S, out2 S)

SetDiff returns the difference between two sets. Returns two slices:

  • out1: elements presented in s1 but missing in s2
  • out2: elements presented in s2 but missing in s1
Example

ExampleSetDiff an example for `SetDiff` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	a := []string{"foo", "bar"}
	b := []string{"bar", "baz"}

	removed, added := slices2.SetDiff(a, b)
	fmt.Println(a, "diff", b)
	fmt.Println("added:", added)
	fmt.Println("removed:", removed)
}
Output:
[foo bar] diff [bar baz]
added: [baz]
removed: [foo]

func SetDiffBy

func SetDiffBy[S ~[]E, E any, K comparable](s1 S, s2 S, byFn func(E) K) (out1 S, out2 S)

SetDiffBy returns the difference between two slices by custom key. Returns two slices:

  • out1: elements presented in s1 but missing in s2
  • out2: elements presented in s2 but missing in s1

The byFn function extracts a comparison key from each element.

func SetOr

func SetOr[S ~[]E, E comparable](s1 S, s2 S) S

SetOr returns the union between two sets. I.e. unique elements presented in at least one slice. Order: first elements from s1, then new elements from s2.

Example

ExampleSetOr an example for `SetOr` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	a := []string{"foo", "bar"}
	b := []string{"bar", "baz"}

	c := slices2.SetOr(a, b)
	fmt.Println(a, "|", b, "=", c)
}
Output:
[foo bar] | [bar baz] = [foo bar baz]

func SetOrBy

func SetOrBy[S ~[]E, E any, K comparable](s1 S, s2 S, byFn func(E) K) S

SetOrBy returns the union between two sets by custom key. I.e. unique elements presented in at least one slice. The byFn function extracts a comparison key from each element. Order: first elements from s1, then new elements from s2.

func SetSub

func SetSub[S ~[]E, E comparable](s1 S, s2 S) S

SetSub returns set where all s2 elements removed from s1. I.e. all elements presented in s1 and missing in s2.

Example

ExampleSetSub an example for `SetSub` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	a := []string{"foo", "bar"}
	b := []string{"bar", "baz"}

	c := slices2.SetSub(a, b)
	fmt.Println(a, "-", b, "=", c)
}
Output:
[foo bar] - [bar baz] = [foo]

func SetSubBy

func SetSubBy[S ~[]E, E any, K comparable](s1 S, s2 S, byFn func(E) K) S

SetSubBy returns set where all s2 elements removed from s1 by custom key. I.e. all elements presented in s1 and missing in s2.

The byFn function extracts a comparison key from each element.

func SortFuncInPlace added in v0.0.3

func SortFuncInPlace[S ~[]E, E any](s S, cmp func(E, E) int)

SortFuncInPlace sorts an input slice s of any type in ascending order using the cmp function. The cmp function should return:

  • negative value if a < b
  • zero if a == b
  • positive value if a > b

This sort is not guaranteed to be stable.

func SortInPlace added in v0.0.3

func SortInPlace[S ~[]E, E cmp.Ordered](s S)

SortInPlace sorts an input slice s of any ordered type in ascending order (in place). This sort is not guaranteed to be stable.

func Sorted added in v0.0.3

func Sorted[S ~[]E, E cmp.Ordered](s S) S

Sorted returns a new slice with elements of input slice s sorted in ascending order. As opposite to SortInPlace, this function always allocates a new array.

Example

ExampleSorted an example for `Sorted` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	s := []int{3, 1, 2}
	r := slices2.Sorted(s)
	fmt.Println(s)
	fmt.Println(r)
}
Output:
[3 1 2]
[1 2 3]

func SortedFunc added in v0.0.3

func SortedFunc[S ~[]E, E any](s S, cmp func(E, E) int) S

SortedFunc returns a new slice with elements of input slice s sorted using the cmp function. As opposite to SortFuncInPlace, this function always allocates a new array.

func ToChannel

func ToChannel[S ~[]E, E any](s S, bufferSize int) <-chan E

ToChannel converts a slice to read-only channel.

All values from slice s will be sent to new channel.

func Transform

func Transform[E2 any, S1 ~[]E1, E1 any](s S1, convFn func(E1) E2) []E2

Transform transforms each slice element from type E1 to type E2. Returns a new slice of transformed elements.

Example

ExampleTransform an example for `Transform` function.

package main

import (
	"fmt"
	"strconv"

	"github.com/Pilatuz/slices2"
)

func main() {
	fromStr := func(s string) int {
		out, _ := strconv.Atoi(s)
		return out
	}
	ss := []string{"123", "456"}
	ii := slices2.Transform(ss, fromStr)
	fmt.Println(ii)
}
Output:
[123 456]

func TransformEx added in v0.0.5

func TransformEx[E2 any, S1 ~[]E1, E1 any](s S1, convFn func(E1) (E2, error)) ([]E2, error)

TransformEx transforms each slice element from type E1 to type E2 with error handling. Stops on the first error. Special error ErrSkip skips elements.

func Unique

func Unique[S ~[]E, E comparable](s S) S

Unique removes duplicates from a slice. Returns new slice with unique elements. Order is preserved (first occurrence remains).

Example

ExampleUnique an example for `Unique` function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	s := []int{4, 1, 2, 1, 2, 3, 2, 1}
	fmt.Println(slices2.Unique(s))
}
Output:
[4 1 2 3]

func UniqueBy

func UniqueBy[S ~[]E, K comparable, E any](s S, byFn func(E) K) S

UniqueBy removes duplicates from a slice by custom key. Returns new slice with unique elements. The byFn function extracts a comparison key from each element. Order is preserved (first occurrence remains).

func UniqueInPlace

func UniqueInPlace[S ~[]E, E comparable](s S) S

UniqueInPlace removes duplicates from a slice. Returns original slice with duplicates removed in-place (no memory allocation). Order is preserved (first occurrence remains).

func UniqueInPlaceBy

func UniqueInPlaceBy[S ~[]E, K comparable, E any](s S, byFn func(E) K) S

UniqueInPlaceBy removes duplicates from a slice by custom key. Returns original slice with duplicates removed in-place (no memory allocation). The byFn function extracts a comparison key from each element. Order is preserved (first occurrence remains).

Types

type Set added in v0.0.6

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

Set represents a collection of unique elements. It's a thin wrapper over map[K]struct{} for convenient set operations.

The Set type supports all basic set operations: add (Push), remove (Pop), check presence (Has, HasAll, HasAny), and get all elements (All).

Example

ExampleSet an example for Set type and its methods.

package main

import (
	"fmt"
	"sort"

	"github.com/Pilatuz/slices2"
)

func main() {
	// Create a new set
	s := slices2.NewSet("foo", "bar", "baz")
	fmt.Println("Set:", s)

	// Check if element exists
	fmt.Println("Has(foo):", s.Has("foo"))
	fmt.Println("Has(qux):", s.Has("qux"))

	// Add elements
	s.Push("qux")
	fmt.Println("After Push(qux):", s)

	// Remove elements
	s.Pop("bar")
	fmt.Println("After Pop(bar):", s)

	// Check all elements (order is not guaranteed, so sort for predictable output)
	all := s.All()
	sort.Strings(all)
	fmt.Println("All():", all) // slices2.Sorted(s.All())

	// Check HasAll
	fmt.Println("HasAll(foo, qux):", s.HasAll("foo", "qux"))
	fmt.Println("HasAll(foo, bar):", s.HasAll("foo", "bar"))

	// Check HasAny
	fmt.Println("HasAny(foo, bar):", s.HasAny("foo", "bar"))
	fmt.Println("HasAny(qux, quux):", s.HasAny("qux", "quux"))
}
Output:
Set: map[bar:{} baz:{} foo:{}]
Has(foo): true
Has(qux): false
After Push(qux): map[bar:{} baz:{} foo:{} qux:{}]
After Pop(bar): map[baz:{} foo:{} qux:{}]
All(): [baz foo qux]
HasAll(foo, qux): true
HasAll(foo, bar): false
HasAny(foo, bar): true
HasAny(qux, quux): true

func NewSet added in v0.0.6

func NewSet[K comparable](kk ...K) Set[K]

NewSet creates a new set with optional elements. Duplicates are automatically removed.

func NewSetBy added in v0.0.6

func NewSetBy[S ~[]E, E any, K comparable](s S, byFn func(E) K) Set[K]

NewSetBy creates a new set from a slice with element transformation via key. The byFn function extracts a key from each element.

Example

ExampleNewSetBy an example for NewSetBy function.

package main

import (
	"fmt"

	"github.com/Pilatuz/slices2"
)

func main() {
	type Person struct {
		Name string
		Age  int
	}
	people := []Person{{"Alice", 30}, {"Bob", 25}, {"Charlie", 30}}
	// Group by age
	ages := slices2.NewSetBy(people, func(p Person) int { return p.Age })
	fmt.Println(ages)
}
Output:
map[25:{} 30:{}]

func (Set[K]) All added in v0.0.6

func (s Set[K]) All() []K

All returns all elements of the set as a slice. Element order is undefined (depends on map implementation). Returns nil for empty sets.

func (Set[K]) Has added in v0.0.6

func (s Set[K]) Has(k K) bool

Has checks if an element is present in the set. Returns true if the element exists.

func (Set[K]) HasAll added in v0.0.6

func (s Set[K]) HasAll(kk ...K) bool

HasAll checks if ALL specified elements are present in the set. Returns true if all elements exist. Empty argument list returns true.

func (Set[K]) HasAny added in v0.0.6

func (s Set[K]) HasAny(kk ...K) bool

HasAny checks if ANY of the specified elements is present in the set. Returns true if at least one element exists in the set. Empty argument list returns false.

func (Set[K]) Pop added in v0.0.6

func (s Set[K]) Pop(kk ...K)

Pop removes elements from the set. Removing non-existent elements is ignored.

func (Set[K]) Push added in v0.0.6

func (s Set[K]) Push(kk ...K)

Push adds elements to the set. Duplicates are ignored.

Jump to

Keyboard shortcuts

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