A comprehensive Go library providing generic, type-safe collection utilities and data structures. Leverages Go generics for efficient slice operations, set management, channel processing, and pointer utilities.
- 🔧 Slice Operations: Filter, Map, Find, Contains, Unique, Reverse, Copy, Exclude, Join
- 📦 Set Data Structure: Thread-safe generic set with mutex protection
- ⚡ Channel Processing: Concurrent channel operations with context support
- 🎯 Pointer Utilities: Generic Ptr/Unptr functions for easy pointer creation
- ⚖️ Comparison Utilities: Generic equality and string comparison helpers
go get github.com/bborbe/collectionimport "github.com/bborbe/collection"
// Filter slice elements
numbers := []int{1, 2, 3, 4, 5}
evens := collection.Filter(numbers, func(n int) bool { return n%2 == 0 })
// Result: [2, 4]
// Create and use a Set
set := collection.NewSet[string]()
set.Add("hello")
set.Add("world")
fmt.Println(set.Contains("hello")) // true
// Create pointers easily
name := "John"
namePtr := collection.Ptr(name) // *string pointing to "John"func Filter[T any](list []T, match func(value T) bool) []TReturns a new slice containing only elements that match the predicate.
users := []User{{Name: "Alice", Age: 25}, {Name: "Bob", Age: 17}}
adults := collection.Filter(users, func(u User) bool { return u.Age >= 18 })func Find[T any](list []T, match func(value T) bool) (*T, error)Returns the first element matching the predicate, or NotFoundError.
user, err := collection.Find(users, func(u User) bool { return u.Name == "Alice" })
if err != nil {
// Handle not found
}func Map[T any](list []T, fn func(value T) error) errorApplies a function to each element in the slice, returning the first error encountered.
err := collection.Map(users, func(u User) error {
return validateUser(u)
})func Unique[T comparable](list []T) []TReturns a new slice with duplicate elements removed, preserving order.
numbers := []int{1, 2, 2, 3, 3, 3}
unique := collection.Unique(numbers) // [1, 2, 3]func Contains[T comparable](list []T, search T) bool
func ContainsAll[T comparable](list []T, search []T) boolCheck if slice contains specific element(s).
fruits := []string{"apple", "banana", "cherry"}
hasApple := collection.Contains(fruits, "apple") // true
hasAll := collection.ContainsAll(fruits, []string{"apple", "banana"}) // truefunc Reverse[T any](list []T) []TReturns a new slice with elements in reverse order.
numbers := []int{1, 2, 3}
reversed := collection.Reverse(numbers) // [3, 2, 1]func Copy[T any](list []T) []TCreates a shallow copy of the slice.
func Exclude[T comparable](list []T, exclude []T) []TReturns a new slice excluding specified elements.
numbers := []int{1, 2, 3, 4, 5}
filtered := collection.Exclude(numbers, []int{2, 4}) // [1, 3, 5]func Join[T ~string](list []T, separator string) stringJoins string-like elements with a separator.
words := []string{"hello", "world", "!"}
sentence := collection.Join(words, " ") // "hello world !"func NewSet[T comparable]() Set[T]Creates a new thread-safe generic set.
stringSet := collection.NewSet[string]()
intSet := collection.NewSet[int]()type Set[T comparable] interface {
Add(element T)
Remove(element T)
Contains(element T) bool
Slice() []T
Length() int
}Example usage:
set := collection.NewSet[string]()
set.Add("apple")
set.Add("banana")
set.Add("apple") // Duplicate, ignored
fmt.Println(set.Length()) // 2
fmt.Println(set.Contains("apple")) // true
fmt.Println(set.Slice()) // ["apple", "banana"] (order not guaranteed)
set.Remove("apple")
fmt.Println(set.Length()) // 1func Ptr[T any](value T) *TCreates a pointer to the given value.
name := "John"
namePtr := collection.Ptr(name) // *string
age := 25
agePtr := collection.Ptr(age) // *intfunc Unptr[T any](ptr *T) T
func UnptrWithDefault[T any](ptr *T, defaultValue T) TDereferences pointers safely.
var namePtr *string = collection.Ptr("John")
name := collection.Unptr(namePtr) // "John"
var nilPtr *string
name := collection.UnptrWithDefault(nilPtr, "Anonymous") // "Anonymous"func ChannelFnMap[T interface{}](
ctx context.Context,
getFn func(ctx context.Context, ch chan<- T) error,
mapFn func(ctx context.Context, t T) error,
) errorProcesses data from a producer function through a mapper function concurrently.
err := collection.ChannelFnMap(
ctx,
func(ctx context.Context, ch chan<- int) error {
for i := 0; i < 100; i++ {
select {
case ch <- i:
case <-ctx.Done():
return ctx.Err()
}
}
return nil
},
func(ctx context.Context, num int) error {
fmt.Printf("Processing: %d\n", num)
return nil
},
)func ChannelFnList[T any](ctx context.Context, getFn func(ctx context.Context, ch chan<- T) error) ([]T, error)
func ChannelFnCount[T any](ctx context.Context, getFn func(ctx context.Context, ch chan<- T) error) (int, error)Collect channel data into a slice or count items.
func Equal[T comparable](a, b T) bool
func Compare[T ~string](a, b T) intGeneric comparison functions for any comparable types.
ctx := context.Background()
// Process items concurrently with automatic batching
err := collection.ChannelFnMap(
ctx,
func(ctx context.Context, ch chan<- WorkItem) error {
return loadWorkItems(ctx, ch) // Your data loading logic
},
func(ctx context.Context, item WorkItem) error {
return processWorkItem(ctx, item) // Your processing logic
},
)// Load raw data
rawData := loadRawData()
// Filter valid entries
validData := collection.Filter(rawData, func(item DataItem) bool {
return item.IsValid()
})
// Remove duplicates
uniqueData := collection.Unique(validData)
// Find specific items
importantItem, err := collection.Find(uniqueData, func(item DataItem) bool {
return item.Priority == "high"
})
// Create a set for fast lookups
processedIDs := collection.NewSet[string]()
for _, item := range uniqueData {
processedIDs.Add(item.ID)
}- Go 1.24.5 or later
- Support for Go generics
github.com/bborbe/errors- Enhanced error handlinggithub.com/bborbe/run- Concurrent execution utilities
go test ./...BSD-style license. See LICENSE file for details.