coll

package
v0.1.11 Latest Latest
Warning

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

Go to latest
Published: Apr 11, 2026 License: GPL-3.0 Imports: 6 Imported by: 0

README

coll

coll is a powerful, type-safe Go library providing functional programming utilities for working with collections (slices, maps, sets, and stacks). Built with Go generics, it offers a rich set of operations for transforming, filtering, and manipulating data structures in a clean, expressive way.

Overview

The coll package provides a comprehensive suite of collection utilities inspired by functional programming patterns. It eliminates boilerplate code for common operations like filtering, mapping, reducing, and grouping, while maintaining type safety through Go's generics system.

Key Features:

  • 🎯 Type-safe generics - works with any type using Go 1.18+ generics
  • 🔄 Functional operations - map, filter, reduce, and more
  • 📦 Multiple data structures - slices, maps, sets, stacks, and hashmaps
  • Zero dependencies - built on Go standard library
  • 🧩 Composable - chain operations for complex transformations
  • 🎨 Immutable operations - most functions return new collections
  • 🔍 Rich API - 40+ utility functions for collection manipulation

Problem Solved: Writing repetitive loops for common collection operations clutters code and increases error risk. coll provides tested, optimized functions that make collection manipulation readable and maintainable.

Use Cases

When to Use
  • Data transformation - convert between types, reshape structures
  • Filtering and searching - find, filter, or check elements
  • Aggregation - sum, count, group, or reduce data
  • Set operations - unique values, intersections, differences
  • Functional pipelines - chain operations for clean data processing
  • Collection utilities - chunk, flatten, partition, shuffle
  • Stack/queue operations - LIFO data structure management
  • HashMap operations - type-safe key-value storage
When Not to Use
  • Simple iterations - use native for loops for basic iteration
  • Performance-critical hot paths - hand-optimized loops may be faster
  • When mutability is required - most functions return new collections
  • Large datasets - consider streaming or database operations
  • Complex queries - use SQL/NoSQL databases for advanced querying

Installation

go get github.com/sivaosorg/replify

Import the package in your Go code:

import "github.com/sivaosorg/replify/pkg/coll"

Requirements: Go 1.18 or higher (for generics support)

Usage

Basic Operations
package main

import (
    "fmt"
    "github.com/sivaosorg/replify/pkg/coll"
)

func main() {
    // Filter even numbers
    numbers := []int{1, 2, 3, 4, 5, 6}
    evens := coll.Filter(numbers, func(n int) bool {
        return n%2 == 0
    })
    fmt.Println(evens) // [2, 4, 6]

    // Map: square each number
    squared := coll.Map(numbers, func(n int) int {
        return n * n
    })
    fmt.Println(squared) // [1, 4, 9, 16, 25, 36]

    // Reduce: sum all numbers
    sum := coll.Reduce(numbers, func(acc, n int) int {
        return acc + n
    }, 0)
    fmt.Println(sum) // 21

    // Check if contains
    hasThree := coll.Contains(numbers, 3)
    fmt.Println(hasThree) // true
}

Examples

1. Filtering and Transformation
type User struct {
    Name  string
    Age   int
    Active bool
}

users := []User{
    {Name: "Alice", Age: 30, Active: true},
    {Name: "Bob", Age: 25, Active: false},
    {Name: "Charlie", Age: 35, Active: true},
}

// Filter active users
activeUsers := coll.Filter(users, func(u User) bool {
    return u.Active
})

// Extract names
names := coll.Map(activeUsers, func(u User) string {
    return u.Name
})
fmt.Println(names) // ["Alice", "Charlie"]

// Get ages of active users
ages := coll.Map(activeUsers, func(u User) int {
    return u.Age
})
2. Reducing and Aggregating
// Sum of numbers
numbers := []int{1, 2, 3, 4, 5}
sum := coll.Reduce(numbers, func(acc, n int) int {
    return acc + n
}, 0)
fmt.Println(sum) // 15

// Calculate total with Sum (using transformer)
type Product struct {
    Name  string
    Price float64
}

products := []Product{
    {Name: "Book", Price: 9.99},
    {Name: "Pen", Price: 1.50},
    {Name: "Notebook", Price: 5.99},
}

totalPrice := coll.Sum(products, func(p Product) float64 {
    return p.Price
})
fmt.Println(totalPrice) // 17.48

// Concatenate strings
words := []string{"Hello", "World", "from", "Go"}
sentence := coll.Reduce(words, func(acc, word string) string {
    return acc + " " + word
}, "")
fmt.Println(sentence) // " Hello World from Go"
3. Finding and Searching
numbers := []int{10, 20, 30, 40, 50}

// Find first element matching condition
first, found := coll.Find(numbers, func(n int) bool {
    return n > 25
})
fmt.Println(first, found) // 30, true

// Find index
index := coll.IndexOf(numbers, 30)
fmt.Println(index) // 2

// Find last index
lastIndex := coll.LastIndexOf([]int{1, 2, 3, 2, 1}, 2)
fmt.Println(lastIndex) // 3

// Check if any element matches
hasLarge := coll.AnyMatch(numbers, func(n int) bool {
    return n > 40
})
fmt.Println(hasLarge) // true

// Check if all elements match
allPositive := coll.AllMatch(numbers, func(n int) bool {
    return n > 0
})
fmt.Println(allPositive) // true
4. Set Operations
// Remove duplicates
numbers := []int{1, 2, 2, 3, 3, 3, 4, 5, 5}
unique := coll.Unique(numbers)
fmt.Println(unique) // [1, 2, 3, 4, 5]

// Intersection
set1 := []int{1, 2, 3, 4}
set2 := []int{3, 4, 5, 6}
intersection := coll.Intersection(set1, set2)
fmt.Println(intersection) // [3, 4]

// Union
union := coll.Union(set1, set2)
fmt.Println(union) // [1, 2, 3, 4, 5, 6]

// Difference
diff := coll.Difference(set1, set2)
fmt.Println(diff) // [1, 2]
5. Chunking and Partitioning
// Chunk into smaller slices
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
chunks := coll.Chunk(numbers, 3)
fmt.Println(chunks) // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

// Partition by condition
evensAndOdds := coll.Partition(numbers, func(n int) bool {
    return n%2 == 0
})
fmt.Println(evensAndOdds) // [[2, 4, 6, 8], [1, 3, 5, 7, 9]]

// Split at index
left, right := coll.Split(numbers, 5)
fmt.Println(left, right) // [1, 2, 3, 4, 5], [6, 7, 8, 9]
6. Grouping and Flattening
// Group by key
type Person struct {
    Name string
    Age  int
}

people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 30},
}

byAge := coll.GroupBy(people, func(p Person) int {
    return p.Age
})
// Result: map[25:[{Bob 25}] 30:[{Alice 30} {Charlie 30}]]

// Flatten nested slices
nested := [][]int{{1, 2}, {3, 4}, {5}}
flat := coll.Flatten[int](convertToInterfaceSlice(nested))
fmt.Println(flat) // [1, 2, 3, 4, 5]
7. Sorting and Shuffling
// Sort with custom comparer
numbers := []int{5, 2, 8, 1, 9}
sorted := coll.Sort(numbers, func(a, b int) bool {
    return a < b // ascending
})
fmt.Println(sorted) // [1, 2, 5, 8, 9]

// Sort descending
descending := coll.Sort(numbers, func(a, b int) bool {
    return a > b
})
fmt.Println(descending) // [9, 8, 5, 2, 1]

// Shuffle randomly
shuffled := coll.Shuffle(numbers)
fmt.Println(shuffled) // Random order

// Reverse
reversed := coll.Reverse(numbers)
fmt.Println(reversed) // [9, 1, 8, 2, 5]
8. Stack Operations
// Create a stack
stack := coll.NewStack[string]()

// Push elements
stack.Push("first")
stack.Push("second")
stack.Push("third")

// Peek at top
top := stack.Peek()
fmt.Println(top) // "third"

// Pop elements
popped := stack.Pop()
fmt.Println(popped) // "third"

// Check if empty
isEmpty := stack.IsEmpty()
fmt.Println(isEmpty) // false

// Get size
size := stack.Size()
fmt.Println(size) // 2

// Clear all
stack.Clear()
9. HashMap Operations
// Create a HashMap
hashMap := coll.NewHashMap[string, int]()

// Set values
hashMap.Set("apple", 5)
hashMap.Set("banana", 3)
hashMap.Set("orange", 7)

// Get value
count, exists := hashMap.Get("apple")
fmt.Println(count, exists) // 5, true

// Check if key exists
hasKey := hashMap.ContainsKey("banana")
fmt.Println(hasKey) // true

// Remove key
hashMap.Remove("orange")

// Get size
size := hashMap.Size()
fmt.Println(size) // 2

// Get all keys
keys := hashMap.Keys()
fmt.Println(keys) // ["apple", "banana"]

// Clear all
hashMap.Clear()
10. HashSet Operations
// Create a HashSet
set := coll.NewHashSet[string]()

// Add elements
set.Add("apple")
set.Add("banana")
set.Add("apple") // Duplicate, won't be added

// Check if contains
hasApple := set.Contains("apple")
fmt.Println(hasApple) // true

// Remove element
set.Remove("banana")

// Get size
size := set.Size()
fmt.Println(size) // 1

// Get all values
values := set.Values()
fmt.Println(values) // ["apple"]

// Clear all
set.Clear()
11. Map Operations
// Check if map contains key
ages := map[string]int{"Alice": 30, "Bob": 25}
hasAlice := coll.ContainsKeyComp(ages, "Alice")
fmt.Println(hasAlice) // true

// Get map keys
keys := coll.Keys(ages)
fmt.Println(keys) // ["Alice", "Bob"]

// Get map values
values := coll.Values(ages)
fmt.Println(values) // [30, 25]

// Merge maps
map1 := map[string]int{"a": 1, "b": 2}
map2 := map[string]int{"b": 3, "c": 4}
merged := coll.MergeMaps(map1, map2)
fmt.Println(merged) // map[a:1 b:3 c:4] (map2 overwrites map1)
12. Slice Utilities
// Take first N elements
numbers := []int{1, 2, 3, 4, 5}
firstThree := coll.Take(numbers, 3)
fmt.Println(firstThree) // [1, 2, 3]

// Skip first N elements
remaining := coll.Skip(numbers, 2)
fmt.Println(remaining) // [3, 4, 5]

// Slice range
middle := coll.SliceRange(numbers, 1, 4)
fmt.Println(middle) // [2, 3, 4]

// Append element
appended := coll.Push(numbers, 6)
fmt.Println(appended) // [1, 2, 3, 4, 5, 6]

// Remove last element
popped := coll.Pop(numbers)
fmt.Println(popped) // [1, 2, 3, 4]

// Check equality
slice1 := []int{1, 2, 3}
slice2 := []int{1, 2, 3}
areEqual := coll.Equal(slice1, slice2)
fmt.Println(areEqual) // true

API Reference

Slice Operations
Transformation
  • Map[T, U](slice []T, f func(T) U) []U - Transform each element
  • FlatMap[T, U](slice []T, mapper func(T) []U) []U - Map and flatten
  • MapWithIndex[T, U](slice []T, mapper func(T, int) U) []U - Map with index
Filtering
  • Filter[T](slice []T, condition func(T) bool) []T - Keep matching elements
  • Reject[T](slice []T, condition func(T) bool) []T - Remove matching elements
  • Compact[T](slice []T) []T - Remove zero values
Searching
  • Contains[T](slice []T, item T) bool - Check if element exists
  • Find[T](slice []T, predicate func(T) bool) (T, bool) - Find first match
  • IndexOf[T](slice []T, item T) int - Get index of element
  • LastIndexOf[T](slice []T, item T) int - Get last index
Aggregation
  • Reduce[T, U](slice []T, accumulator func(U, T) U, initial U) U - Reduce to single value
  • Sum[T](slice []T, transformer func(T) float64) float64 - Sum transformed values
Predicates
  • AllMatch[T](slice []T, predicate func(T) bool) bool - Check if all match
  • AnyMatch[T](slice []T, predicate func(T) bool) bool - Check if any match
  • NoneMatch[T](slice []T, predicate func(T) bool) bool - Check if none match
Set Operations
  • Unique[T](slice []T) []T - Remove duplicates
  • Intersection[T](a, b []T) []T - Common elements
  • Union[T](a, b []T) []T - All unique elements from both
  • Difference[T](a, b []T) []T - Elements in a but not in b
Partitioning
  • Chunk[T](slice []T, size int) [][]T - Split into chunks
  • Partition[T](slice []T, predicate func(T) bool) ([]T, []T) - Split by condition
  • GroupBy[T, K](slice []T, keyFunc func(T) K) map[K][]T - Group by key
  • Split[T](slice []T, index int) ([]T, []T) - Split at index
Ordering
  • Sort[T](slice []T, comparer func(T, T) bool) []T - Custom sort
  • Reverse[T](slice []T) []T - Reverse order
  • Shuffle[T](slice []T) []T - Random order
Utilities
  • Take[T](slice []T, n int) []T - First N elements
  • Skip[T](slice []T, n int) []T - Skip first N elements
  • Push[T](slice []T, element T) []T - Append element
  • Pop[T](slice []T) []T - Remove last element
  • Flatten[T](slice []any) []T - Flatten nested slices
  • Equal[T](a, b []T) bool - Check equality
Map Operations
  • Map[T, U](slice []T, f func(T) U) []U - Transform elements
  • ContainsKeyComp[K, V](m map[K]V, key K) bool - Check if key exists
  • Keys[K, V](m map[K]V) []K - Get all keys
  • Values[K, V](m map[K]V) []V - Get all values
  • MergeMaps[K, V](maps ...map[K]V) map[K]V - Merge multiple maps
Stack[T comparable]
  • NewStack[T]() *Stack[T] - Create new stack
  • Push(element T) - Add to top
  • Pop() T - Remove and return top
  • Peek() T - View top without removing
  • IsEmpty() bool - Check if empty
  • Size() int - Get number of elements
  • Clear() - Remove all elements
HashMap[K, V comparable]
  • NewHashMap[K, V]() *HashMap[K, V] - Create new hashmap
  • Set(key K, value V) - Set key-value pair
  • Get(key K) (V, bool) - Get value by key
  • ContainsKey(key K) bool - Check if key exists
  • Remove(key K) - Remove key-value pair
  • Keys() []K - Get all keys
  • Size() int - Get number of pairs
  • Clear() - Remove all pairs
HashSet[T comparable]
  • NewHashSet[T]() *HashSet[T] - Create new set
  • Add(item T) - Add element
  • Contains(item T) bool - Check if element exists
  • Remove(item T) - Remove element
  • Values() []T - Get all values
  • Size() int - Get number of elements
  • Clear() - Remove all elements

Best Practices & Notes

⚠️ Common Pitfalls
  1. Mutability: Most functions return new collections, not modifying originals

    // ❌ Wrong: expecting mutation
    numbers := []int{1, 2, 3}
    coll.Filter(numbers, func(n int) bool { return n > 1 })
    // numbers is still [1, 2, 3]
    
    // ✅ Correct: capture return value
    filtered := coll.Filter(numbers, func(n int) bool { return n > 1 })
    
  2. Empty Slices: Some functions may panic on empty slices

    // ❌ Panics
    empty := []int{}
    coll.Pop(empty) // Runtime panic
    
    // ✅ Check length first
    if len(slice) > 0 {
        popped := coll.Pop(slice)
    }
    
  3. Performance: Creating new slices has memory overhead

    // ❌ Inefficient for large datasets
    for i := 0; i < 1000000; i++ {
        result = coll.Push(result, i) // Reallocates each time
    }
    
    // ✅ Pre-allocate when possible
    result := make([]int, 0, 1000000)
    for i := 0; i < 1000000; i++ {
        result = append(result, i)
    }
    
  4. Type Inference: Sometimes you need explicit type parameters

    // ❌ May fail to infer
    result := coll.Map(data, transform)
    
    // ✅ Explicit types
    result := coll.Map[Input, Output](data, transform)
    
💡 Recommendations

Chain operations for readable pipelines

result := coll.Filter(data, isValid)
result = coll.Map(result, transform)
result = coll.Sort(result, compare)

Use method chaining alternative

// Consider creating a fluent API wrapper for your use case
type Pipeline[T any] struct {
    data []T
}

func (p Pipeline[T]) Filter(f func(T) bool) Pipeline[T] {
    return Pipeline[T]{coll.Filter(p.data, f)}
}

Leverage type safety - let compiler catch errors

// Compile-time safety
users := []User{}
names := coll.Map(users, func(u User) string { return u.Name })
// names is []string, enforced by compiler

Document complex transformations with comments

// Transform users to active user emails
emails := coll.Map(
    coll.Filter(users, func(u User) bool { return u.Active }),
    func(u User) string { return u.Email },
)

Consider performance for large datasets

  • Use native loops for simple iterations
  • Profile before optimizing
  • Consider streaming for huge datasets

Use appropriate data structures

  • Stack for LIFO operations
  • HashSet for uniqueness checks
  • HashMap for key-value lookups
  • Slices for ordered data
🔒 Thread Safety

Not thread-safe by default. All data structures and operations assume single-threaded access.

// ❌ Unsafe concurrent access
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        stack.Push(i) // Race condition!
    }()
}

// ✅ Use mutex for concurrent access
var mu sync.Mutex
stack := coll.NewStack[int]()

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(val int) {
        defer wg.Done()
        mu.Lock()
        stack.Push(val)
        mu.Unlock()
    }(i)
}
⚡ Performance Tips

Benchmark before optimizing:

func BenchmarkCollMap(b *testing.B) {
    data := generateLargeSlice()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        coll.Map(data, transform)
    }
}

Performance characteristics:

  • Map, Filter: O(n)
  • Contains, IndexOf: O(n)
  • Unique: O(n) with map
  • Sort: O(n log n)
  • Intersection, Union: O(n + m)
  • Flatten: O(n × depth)

Optimization strategies:

  1. Pre-allocate slices when size is known
  2. Use break in for loops for early exit
  3. Avoid nested Map/Filter - combine logic
  4. Use HashMap for frequent lookups
  5. Consider native loops for hot paths
🐛 Debugging Tips

Print intermediate results:

filtered := coll.Filter(data, condition)
fmt.Printf("After filter: %v\n", filtered)

mapped := coll.Map(filtered, transform)
fmt.Printf("After map: %v\n", mapped)

Use meaningful function names:

// ❌ Unclear
coll.Filter(users, func(u User) bool { return u.A > 18 && u.S == "active" })

// ✅ Clear
isEligible := func(u User) bool {
    return u.Age > 18 && u.Status == "active"
}
coll.Filter(users, isEligible)

Test edge cases:

  • Empty slices
  • Single element
  • All elements match/don't match
  • Duplicates
  • Nested structures
📝 Testing

Example test cases:

func TestFilter(t *testing.T) {
    tests := []struct {
        name   string
        input  []int
        pred   func(int) bool
        want   []int
    }{
        {"empty", []int{}, func(n int) bool { return n > 0 }, []int{}},
        {"all match", []int{1, 2, 3}, func(n int) bool { return n > 0 }, []int{1, 2, 3}},
        {"none match", []int{1, 2, 3}, func(n int) bool { return n > 10 }, []int{}},
        {"some match", []int{1, 2, 3, 4}, func(n int) bool { return n%2 == 0 }, []int{2, 4}},
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := coll.Filter(tt.input, tt.pred)
            if !coll.Equal(got, tt.want) {
                t.Errorf("Filter() = %v, want %v", got, tt.want)
            }
        })
    }
}

Limitations

  • No lazy evaluation - all operations are eager (process entire collection)
  • Memory overhead - most operations create new collections
  • No parallel processing - all operations are sequential
  • Limited to comparable types - some structures require comparable types
  • No query optimization - operations are applied in order given
  • Stack size limits - recursive operations may hit stack limits on huge nested data

Performance Considerations

When to use native loops:

  • Simple iteration with no transformation
  • Performance-critical sections (after profiling)
  • When you need early termination with complex logic
  • Mutation of existing slices

When to use coll:

  • Complex transformations with multiple steps
  • Readability is more important than micro-optimization
  • Working with functional patterns
  • Rapid prototyping
  • Most business logic (not hot paths)

Contributing

Contributions are welcome! Please see the main replify repository for contribution guidelines.

License

This library is part of the replify project.

Part of the replify ecosystem:

  • replify - API response wrapping library
  • conv - Type conversion utilities
  • hashy - Deterministic hashing
  • match - Wildcard pattern matching
  • Other sivaosorg utilities

Note: The search results shown above may be incomplete due to GitHub's result limits. For a complete view of all functions, please visit the coll package on GitHub.

Documentation

Overview

Package coll provides generic collection types and functional utilities for working with slices and maps in Go.

The package is organised into three layers:

  1. Concrete collection types – HashMap, HashSet, and Stack – each backed by the corresponding standard Go data structure and exposed through a typed, method-based API.

  2. Map utilities – standalone functions for transforming, merging, filtering, flattening, and inverting maps with full type-parameter support.

  3. Slice utilities – higher-order functions such as Map, Filter, Reduce, Chunk, and ZipWith that operate on slices of any element type.

Generic Collection Types

HashMap[K, V comparable] is a typed wrapper around Go's built-in map that provides Put, Get, Remove, ContainsKey, KeySet, and Clear operations:

m := coll.NewHashMap[string, int]()
m.Put("hits", 42)
fmt.Println(m.Get("hits")) // 42

HashSet[T comparable] stores unique elements and supports set-algebra operations including Intersection, Union, and Difference:

s := coll.NewHashSet("a", "b", "c")
s.Add("d")
fmt.Println(s.Contains("b")) // true

Stack[T comparable] implements a last-in, first-out (LIFO) structure with Push, Pop, Peek, and IsEmpty:

stack := coll.NewStack[int]()
stack.Push(1)
stack.Push(2)
fmt.Println(stack.Pop()) // 2

Map Utilities

MergeComp, DeepMerge, FlattenMap, UnflattenMap, PickComp, OmitComp, and InvertComp cover the most common map transformation patterns. Functions whose names end in Comp accept keys constrained to comparable, while their non-Comp counterparts accept map[any]V for looser typing.

Slice Utilities

Map and ToSlice transform each element, ToMap indexes a slice by a key function, and GetOrDefault provides a safe fallback for map lookups.

All functions are safe for concurrent use if the underlying collections are not mutated during the call. The collection types themselves are not goroutine-safe; external synchronisation is required when sharing instances across goroutines.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllMatch

func AllMatch[T any](slice []T, predicate func(T) bool) bool

AllMatch checks if all elements in a slice satisfy a given condition and returns a boolean result.

This function takes an input slice `slice` and a predicate function `predicate`. It iterates over each element in the slice, applying the predicate function to each one. If any element does not satisfy the predicate (i.e., the predicate returns `false`), the function immediately returns `false`. If all elements satisfy the predicate, the function returns `true`.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice whose elements will be checked. It can contain elements of any type `T`.
  • `predicate`: A function that takes an element of type `T` and returns a boolean. This function represents the condition that each element must satisfy. If the predicate returns `true` for an element, the element meets the condition.

Returns:

  • `true` if all elements in the slice satisfy the predicate; `false` if any element does not.

Example:

// Checking if all integers in a slice are positive
numbers := []int{2, 4, 6, 8}
allPositive := AllMatch(numbers, func(n int) bool {
	return n > 0
})
// allPositive will be true

// Checking if all strings in a slice have a length greater than 3
words := []string{"apple", "banana", "pear"}
allLong := AllMatch(words, func(s string) bool {
	return len(s) > 3
})
// allLong will be true

// If the slice is empty, returns true since no elements violate the predicate
empty := []int{}
allMatchEmpty := AllMatch(empty, func(n int) bool {
	return n > 0
})
// allMatchEmpty will be true

func AnyMatch

func AnyMatch[T any](slice []T, predicate func(T) bool) bool

AnyMatch checks if any element in a slice satisfies a given condition and returns a boolean result.

This function takes an input slice `slice` and a predicate function `predicate`. It iterates over each element in the slice, applying the predicate function to each one. If the predicate returns `true` for any element, the function immediately returns `true`. If no elements satisfy the predicate, the function returns `false`.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice whose elements will be checked. It can contain elements of any type `T`.
  • `predicate`: A function that takes an element of type `T` and returns a boolean. This function represents the condition that an element must satisfy. If the predicate returns `true` for an element, the element meets the condition.

Returns:

  • `true` if at least one element in the slice satisfies the predicate; `false` if no elements do.

Example:

// Checking if any integers in a slice are even
numbers := []int{1, 3, 5, 6}
anyEven := AnyMatch(numbers, func(n int) bool {
	return n%2 == 0
})
// anyEven will be true because 6 is even

// Checking if any strings in a slice contain the letter "a"
words := []string{"apple", "banana", "cherry"}
containsA := AnyMatch(words, func(s string) bool {
	return strings.Contains(s, "a")
})
// containsA will be true because "apple" and "banana" contain "a"

// Checking an empty slice returns false since no elements satisfy the predicate
empty := []int{}
anyMatchEmpty := AnyMatch(empty, func(n int) bool {
	return n > 0
})
// anyMatchEmpty will be false

func AppendIf

func AppendIf[T comparable](slice []T, element T) []T

AppendIf appends an element to a slice if it is not already present.

This function takes an input slice `slice` and an element `element`. It first checks if the element is already in the slice by calling the helper function `ContainsN`. If the element is not found in the slice, the function appends it to the end of the slice. If the element is already present, the original slice is returned unchanged.

The function is generic and requires that the type `T` be `comparable`, allowing the function to use the `==` operator in `ContainsN` to check for equality.

Parameters:

  • `slice`: The input slice to which the element might be appended. It can contain elements of any comparable type `T`.
  • `element`: The element to be appended if it is not already in `slice`. It is of type `T`.

Returns:

  • A new slice of type `[]T` containing the original elements and, if missing, the appended `element`.

Example:

// Adding a missing integer to a slice
numbers := []int{1, 2, 3}
updatedNumbers := AppendIf(numbers, 4)
// updatedNumbers will be []int{1, 2, 3, 4}

// Trying to add an existing integer to a slice
updatedNumbers = AppendIf(numbers, 3)
// updatedNumbers will be []int{1, 2, 3} (unchanged)

// Adding a missing string to a slice
words := []string{"apple", "banana"}
updatedWords := AppendIf(words, "cherry")
// updatedWords will be []string{"apple", "banana", "cherry"}

func Cartesian

func Cartesian[T any](slices ...[]T) [][]T

Cartesian computes the Cartesian product of multiple slices and returns the result as a slice of slices.

This function takes multiple slices of type `[]T` and computes their Cartesian product. The Cartesian product of two or more sets (or slices in this case) is the set of all possible combinations where each combination consists of one element from each slice. The function recursively computes the product of the slices, starting from the second slice and combining it with each element of the first slice. The result is a slice of slices, where each inner slice is a combination of elements from the input slices.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slices`: A variadic parameter that represents multiple slices to compute the Cartesian product of. Each slice can contain elements of any type `T`.

Returns:

  • A slice of slices (`[][]T`), where each inner slice represents a unique combination of elements from the input slices.

Example:

// Cartesian product of two slices of integers
slice1 := []int{1, 2}
slice2 := []int{3, 4}
product := Cartesian(slice1, slice2)
// product will be [][]int{{1, 3}, {1, 4}, {2, 3}, {2, 4}}

// Cartesian product of three slices of strings
slice3 := []string{"a", "b"}
slice4 := []string{"x", "y"}
slice5 := []string{"1", "2"}
productStrings := Cartesian(slice3, slice4, slice5)
// productStrings will be [][]string{
//   {"a", "x", "1"}, {"a", "x", "2"},
//   {"a", "y", "1"}, {"a", "y", "2"},
//   {"b", "x", "1"}, {"b", "x", "2"},
//   {"b", "y", "1"}, {"b", "y", "2"}
// }

// Cartesian product of an empty slice returns an empty slice
empty := []int{}
productEmpty := Cartesian(empty)
// productEmpty will be [][]int{{}}

func Chunk

func Chunk[T any](slice []T, chunkSize int) [][]T

Chunk splits a slice into smaller slices (chunks) of the specified size.

This function takes an input slice `slice` and a `chunkSize` and splits the input slice into smaller slices, each containing up to `chunkSize` elements. The function returns a slice of slices containing the chunked elements. If the `chunkSize` is greater than the length of the input slice, the entire slice will be returned as a single chunk. If the `chunkSize` is less than or equal to 0, the function returns `nil`.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice to be split into chunks. It can contain elements of any type `T`.
  • `chunkSize`: The size of each chunk. If this value is less than or equal to 0, the function returns `nil`.

Returns:

  • A slice of slices (`[][]T`), where each inner slice contains up to `chunkSize` elements from the original slice. If the slice cannot be split into even chunks, the last chunk may contain fewer elements than `chunkSize`.

Example:

// Chunking a slice of integers into chunks of size 2
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
chunks := Chunk(numbers, 2)
// chunks will be [][]int{{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9}}

// Chunking a slice of strings into chunks of size 3
words := []string{"apple", "banana", "cherry", "date", "elderberry", "fig"}
chunksWords := Chunk(words, 3)
// chunksWords will be [][]string{{"apple", "banana", "cherry"}, {"date", "elderberry", "fig"}}

// Chunking an empty slice returns an empty slice of slices
empty := []int{}
chunksEmpty := Chunk(empty, 3)
// chunksEmpty will be [][]int{}

// If chunkSize is 0 or negative, return nil
chunksInvalid := Chunk(numbers, -1)
// chunksInvalid will be nil

func Concat

func Concat[T any](slices ...[]T) []T

Concat returns a new slice that is the result of concatenating multiple input slices into a single slice.

This function takes a variable number of slices as input and combines them into one contiguous slice. It first calculates the total length needed for the resulting slice, then copies each input slice into the appropriate position within the resulting slice.

The function is generic, allowing it to concatenate slices of any type `T`.

Parameters:

  • `slices`: A variadic parameter representing the slices to concatenate. Each slice can contain elements of any type `T`, and they will be concatenated in the order they are provided.

Returns:

  • A new slice of type `[]T` containing all elements from each input slice in sequence.

Example:

// Concatenating integer slices
a := []int{1, 2}
b := []int{3, 4}
c := []int{5, 6}
combined := Concat(a, b, c)
// combined will be []int{1, 2, 3, 4, 5, 6}

// Concatenating string slices
words1 := []string{"hello", "world"}
words2 := []string{"go", "lang"}
concatenatedWords := Concat(words1, words2)
// concatenatedWords will be []string{"hello", "world", "go", "lang"}

func Contains

func Contains[T comparable](array []T, item T) bool

Contains checks if a specified item is present within a given slice.

This function iterates over a slice of any type that supports comparison and checks if the specified `item` exists within it. It returns `true` if the `item` is found and `false` otherwise.

The function is generic, so it can be used with any comparable type, including strings, integers, floats, or custom types that implement the comparable interface.

Parameters:

  • `array`: The slice of elements to search through. This slice can contain any type `T` that supports comparison (e.g., int, string).
  • `item`: The item to search for within `array`. It should be of the same type `T` as the elements in `array`.

Returns:

  • `true` if `item` is found within `array`, `false` otherwise.

Example:

numbers := []int{1, 2, 3, 4, 5}
isPresent := Contains(numbers, 3) // isPresent will be true as 3 is in the slice

names := []string{"Alice", "Bob", "Charlie"}
isPresent := Contains(names, "Eve") // isPresent will be false as "Eve" is not in the slice

func ContainsKeyComp

func ContainsKeyComp[K comparable, V any](m map[K]V, key K) bool

ContainsKeyComp checks if a specified key is present within a given map.

This function takes a map with keys of any comparable type `K` and values of any type `V`. It checks if the specified `key` exists in the map `m`. If the key is found, it returns `true`; otherwise, it returns `false`.

The function is generic and can be used with maps that have keys of any type that supports comparison (e.g., int, string). The value type `V` can be any type.

Parameters:

  • `m`: The map in which to search for the key. The map has keys of type `K` and values of type `V`.
  • `key`: The key to search for within `m`. It should be of the same type `K` as the keys in `m`.

Returns:

  • `true` if `key` is found in `m`, `false` otherwise.

Example:

ages := map[string]int{"Alice": 30, "Bob": 25}
isPresent := ContainsKeyComp(ages, "Alice") // isPresent will be true as "Alice" is a key in the map

prices := map[int]float64{1: 9.99, 2: 19.99}
isPresent := ContainsKeyComp(prices, 3) // isPresent will be false as 3 is not a key in the map

func DeepMerge

func DeepMerge(dst, src map[string]any) map[string]any

DeepMerge merges two maps, deeply combining values from the source map into the target map.

This function takes two maps: `target` and `source`, both with string keys and interface{} values. It recursively merges the values from the `source` map into the `target` map. If a key exists in both maps, the function checks if the values associated with the key are themselves maps. If so, it recursively merges the nested maps. Otherwise, it directly overwrites the target map's value with the value from the source map. This function allows for deep merging of nested maps.

The function modifies the `target` map in place and does not return anything.

Parameters:

  • `target`: The map that will be updated with values from the `source`. It is modified in place.
  • `source`: The map whose values will be merged into the `target`.

Example:

// Merging two maps with nested maps
target := map[string]interface{}{
	"fruit": map[string]interface{}{"apple": 5, "banana": 10},
	"vegetable": map[string]interface{}{"carrot": 3},
}
source := map[string]interface{}{
	"fruit": map[string]interface{}{"banana": 7, "orange": 2},
	"vegetable": map[string]interface{}{"spinach": 5},
	"grain": 100,
}
DeepMerge(target, source)
// target will now be:
// map[string]interface{}{
//		"fruit": map[string]interface{}{"apple": 5, "banana": 7, "orange": 2},
//		"vegetable": map[string]interface{}{"carrot": 3, "spinach": 5},
//		"grain": 100,
//	}

// If there is no conflict, the value from the source is added as is.
// If the source value is a nested map, the function will perform a deep merge.

func Difference

func Difference[T comparable](slice1, slice2 []T) []T

Difference returns a new slice containing elements that are unique to each of the two input slices.

This function takes two input slices, `slice1` and `slice2`, and identifies elements that are present in either slice but not both. It creates a map to track the elements of `slice1`, then checks for unique elements in `slice2` by confirming that they are not present in `slice1`. Finally, it appends any unique elements from `slice1` to ensure that the result includes all elements unique to either slice.

The function is generic, allowing it to work with slices of any `comparable` type `T`.

Parameters:

  • `slice1`: The first input slice containing elements of any comparable type `T`.
  • `slice2`: The second input slice containing elements of any comparable type `T`.

Returns:

  • A new slice of type `[]T` that contains elements unique to either `slice1` or `slice2`. If an element appears in both slices, it will not appear in the result.

Example:

// Finding unique integers between two slices
numbers1 := []int{1, 2, 3, 4}
numbers2 := []int{3, 4, 5, 6}
uniqueNumbers := Difference(numbers1, numbers2)
// uniqueNumbers will be []int{1, 2, 5, 6}

// Finding unique strings between two slices
words1 := []string{"apple", "banana", "cherry"}
words2 := []string{"banana", "date"}
uniqueWords := Difference(words1, words2)
// uniqueWords will be []string{"apple", "cherry", "date"}

// Difference with an empty slice results in the original slice
empty := []int{}
uniqueFromEmpty := Difference(numbers1, empty)
// uniqueFromEmpty will be []int{1, 2, 3, 4}

func Equal

func Equal[T comparable](a []T, b []T) bool

Equal checks if two slices are equal in both length and elements.

This function compares two slices `a` and `b` of any comparable type `T`. It first checks if the lengths of the two slices are the same. If they are not, it returns `false`. If the lengths match, it then iterates through each element in `a` and `b` to check if corresponding elements are equal. If all elements are equal, the function returns `true`; otherwise, it returns `false`.

The function is generic and can be used with slices of any comparable type, such as integers, strings, or other types that support equality comparison.

Parameters:

  • `a`: The first slice to compare. It should contain elements of a comparable type `T`.
  • `b`: The second slice to compare. It should also contain elements of type `T`.

Returns:

  • `true` if both slices have the same length and identical elements at each position; `false` otherwise.

Example:

// Comparing integer slices
a := []int{1, 2, 3}
b := []int{1, 2, 3}
isEqual := Equal(a, b)
// isEqual will be true as both slices contain the same elements in the same order

c := []int{1, 2, 4}
isEqual = Equal(a, c)
// isEqual will be false as the elements differ

// Comparing string slices
names1 := []string{"Alice", "Bob"}
names2 := []string{"Alice", "Bob"}
isEqual = Equal(names1, names2)
// isEqual will be true since the slices have identical elements

func Filter

func Filter[T any](list []T, condition func(T) bool) []T

Filter returns a new slice containing only the elements from the input slice that satisfy a specified condition.

This function iterates over each element in the input slice `list` and applies the provided `condition` function to it. If the `condition` function returns `true` for an element, that element is added to the `filtered` slice. At the end, the function returns the `filtered` slice containing only the elements that met the condition.

The function is generic, allowing it to work with slices of any type `T` and any condition function that takes a `T` and returns a boolean.

Parameters:

  • `list`: The slice of elements to filter. It can contain elements of any type `T`.
  • `condition`: A function that defines the filtering criteria. It takes an element of type `T` as input and returns `true` if the element should be included in the result, or `false` if it should be excluded.

Returns:

  • A new slice of type `[]T` containing only the elements from `list` for which the `condition` function returned `true`.

Example:

numbers := []int{1, 2, 3, 4, 5}
oddNumbers := Filter(numbers, func(n int) bool { return n%2 != 0 })
// oddNumbers will be []int{1, 3, 5} as only the odd numbers satisfy the condition

words := []string{"apple", "banana", "cherry"}
longWords := Filter(words, func(word string) bool { return len(word) > 5 })
// longWords will be []string{"banana", "cherry"} as they are longer than 5 characters

func FilterMap

func FilterMap[K any, V any](m map[any]V, filter func(V) bool) map[any]V

FilterMap filters the key-value pairs of a map based on a condition provided by the filter function.

This function iterates over each key-value pair in the input map `m` and applies the provided `filter` function to the value. If the `filter` function returns `true` for a value, that key-value pair is added to the `filteredMap`. Otherwise, the pair is excluded. The function returns a new map containing only the key-value pairs that satisfy the condition specified in the `filter` function.

The function is generic, allowing it to work with maps where the keys and values can be of any type `K` and `V`, respectively.

Parameters:

  • `m`: The input map to be filtered, with keys of type `any` and values of type `V`.
  • `filter`: A function that takes a value of type `V` and returns a boolean. It determines whether the corresponding key-value pair should be included in the result map.

Returns:

  • A new map of type `map[any]V`, containing only the key-value pairs for which the `filter` function returned `true`.

Example:

// Filtering a map of integers, keeping only values greater than 10
map1 := map[any]int{"a": 5, "b": 15, "c": 20}
filtered := FilterMap(map1, func(v int) bool {
	return v > 10
})
// filtered will be map[any]int{"b": 15, "c": 20}

// Filtering a map of strings, keeping only values with length greater than 3
map2 := map[any]string{"a": "apple", "b": "banana", "c": "cat"}
filteredStrings := FilterMap(map2, func(v string) bool {
	return len(v) > 3
})
// filteredStrings will be map[any]string{"a": "apple", "b": "banana"}

// Filtering an empty map returns an empty map
emptyMap := map[any]int{}
filteredEmpty := FilterMap(emptyMap, func(v int) bool {
	return v > 10
})
// filteredEmpty will be an empty map

func FindIndex

func FindIndex[T comparable](slice []T, target T) int

FindIndex searches for the first occurrence of a target element in a slice and returns its index. If the element is not found, it returns -1.

This function iterates over each element in the input slice `slice` and compares each element to the specified `target`. When the first occurrence of `target` is found, the function returns the index of that element. If the element is not found, the function returns -1 to indicate that the target is not present in the slice.

The function is generic, allowing it to work with slices of any comparable type `T`, such as integers, strings, or other types that support equality comparison.

Parameters:

  • `slice`: The input slice in which to search for the target element. It can contain elements of any comparable type `T`.
  • `target`: The element to search for within the slice. It should be of the same type `T` as the elements in `slice`.

Returns:

  • The zero-based index of the first occurrence of `target` in the slice if it exists; otherwise, -1 if the target is not found.

Example:

// Searching for an integer in a slice
numbers := []int{1, 2, 3, 4}
index := FindIndex(numbers, 3)
// index will be 2, as 3 is located at index 2 in the slice

// Searching for a string in a slice
words := []string{"apple", "banana", "cherry"}
index = FindIndex(words, "banana")
// index will be 1, as "banana" is at index 1 in the slice

// Item not found in the slice
index = FindIndex(words, "date")
// index will be -1, as "date" is not in the slice

func Flatten

func Flatten[T any](s []any) []T

Flatten takes a slice of potentially nested elements and returns a new slice containing all elements of type `T` in a flat structure.

This function recursively processes each element in the input slice `s`, checking if it is a nested slice (`[]interface{}`). If a nested slice is found, `Flatten` is called recursively to flatten it and append its elements to the `result` slice. If an element is of type `T`, it is directly appended to `result`. Elements that are neither `[]interface{}` nor of type `T` are ignored.

The function is generic, allowing it to work with any element type `T`, which must be specified when calling the function. This makes `Flatten` useful for flattening slices with nested structures while filtering only the elements of a specified type.

Parameters:

  • `s`: A slice of `interface{}`, which can contain nested slices (`[]interface{}`) or elements of any type. Nested slices may contain more nested slices at arbitrary depths.

Returns:

  • A new slice of type `[]T` containing all elements of type `T` from `s`, flattened into a single level.

Example:

// Flattening a nested slice of integers
nestedInts := []interface{}{1, []interface{}{2, 3}, []interface{}{[]interface{}{4, 5}}}
flatInts := Flatten[int](nestedInts)
// flatInts will be []int{1, 2, 3, 4, 5}

// Flattening a nested slice with mixed types, extracting only strings
mixedNested := []interface{}{"apple", []interface{}{"banana", 1, []interface{}{"cherry"}}}
flatStrings := Flatten[string](mixedNested)
// flatStrings will be []string{"apple", "banana", "cherry"}

// Flattening an empty slice
empty := []interface{}{}
flatEmpty := Flatten[int](empty)
// flatEmpty will be []int{}

func FlattenDeep

func FlattenDeep(arr any) []any

FlattenDeep takes a nested structure of arbitrary depth and returns a flat slice containing all elements in a single level.

This function recursively processes each element in `arr`. If an element is itself a slice (`[]interface{}`), `FlattenDeep` calls itself to flatten that nested slice and appends its elements to the `result` slice. If the element is not a slice, it is directly added to `result`. The function allows flattening of complex nested structures while maintaining all elements in a single-level output.

This function operates with values of type `interface{}`, making it flexible enough to handle mixed types in the input. It returns a slice of `interface{}`, which may contain elements of varying types from the original nested structure.

Parameters:

  • `arr`: The input slice, which can contain nested slices of arbitrary depth and elements of any type.

Returns:

  • A slice of `[]interface{}` containing all elements from `arr` flattened into a single level.

Example:

// Flattening a nested structure of mixed values
nested := []interface{}{1, []interface{}{2, 3, []interface{}{4, []interface{}{5}}}}
flat := FlattenDeep(nested)
// flat will be []interface{}{1, 2, 3, 4, 5}

// Flattening a deeply nested structure with varied types
mixedNested := []interface{}{"apple", []interface{}{"banana", 1, []interface{}{"cherry"}}}
flatMixed := FlattenDeep(mixedNested)
// flatMixed will be []interface{}{"apple", "banana", 1, "cherry"}

// Flattening a non-nested input returns the input as-is
nonNested := 5
flatNonNested := FlattenDeep(nonNested)
// flatNonNested will be []interface{}{5}

func FlattenMap

func FlattenMap(m map[string]any, prefix string) map[string]any

FlattenMap flattens a nested map into a single-level map with dot-separated keys.

This function takes a nested map `m` where the keys are strings and the values can be either primitive values or other nested maps. It recursively traverses the nested structure, constructing new keys by concatenating parent keys with child keys using a dot (".") as a separator.

The function returns a new map where all nested keys are flattened into a single level, with the keys representing the path to each value in the original nested map.

Parameters:

  • `m`: The nested map to be flattened. It has string keys and values of type `any`.
  • `prefix`: A string prefix used to build the keys during recursion. This is typically an empty string when the function is called initially.

Returns:

  • A new map of type `map[string]any`, where all nested keys from the input map `m` are flattened into a single level with dot-separated keys.

Example:

nestedMap := map[string]any{
	"user": map[string]any{
		"name": "Alice",
		"address": map[string]any{
			"city": "Wonderland",
			"zip":  "12345",
		},
	},
	"age": 30,
}
flattened := FlattenMap(nestedMap, "")
// flattened will be:
// map[string]any{
//		"user.name": "Alice",
//		"user.address.city": "Wonderland",
//		"user.address.zip": "12345",
//		"age": 30,
// }

func GetOrDefault

func GetOrDefault[K comparable, V any](m map[K]V, key K, defaultValue V) V

GetOrDefault retrieves the value for a given key from the map.

This function checks if the specified `key` exists in the map `m`. If the key is found, it returns the corresponding value. If the key is not found, it returns the provided `defaultValue`.

The function is generic, allowing it to work with maps where the keys are of any comparable type `K` and the values are of any type `V`.

Parameters:

  • `m`: The map from which to retrieve the value. It has keys of type `K` and values of type `V`.
  • `key`: The key to look for in the map. It should be of the same type `K` as the keys in `m`.
  • `defaultValue`: The value to return if the key is not found in the map.

Returns:

  • The value associated with the specified `key` if it exists in the map `m`.
  • The `defaultValue` if the key is not found.

Example:

// Retrieving a value from a map with a default fallback
m := map[string]int{"a": 1, "b": 2, "c": 3}
value := GetOrDefault(m, "b", 0)
// value will be 2 as "b" exists in the map

func GroupBy

func GroupBy[T any, K comparable](slice []T, getKey func(T) K) map[K][]T

GroupBy groups elements of a slice into a map based on a specified key.

This function iterates over each element in the input slice `slice`, applies the provided `getKey` function to extract a key for each element, and groups elements that share the same key into a slice. The function then returns a map where each key maps to a slice of elements that correspond to that key.

The function is generic, allowing it to work with slices of any type `T` and to generate keys of any comparable type `K`. This makes `GroupBy` useful for organizing data based on shared attributes, such as grouping items by category or organizing records by a specific field.

Parameters:

  • `slice`: The input slice containing elements to be grouped. It can be of any type `T`.
  • `getKey`: A function that takes an element of type `T` and returns a key of type `K`, which is used to group the element in the resulting map.

Returns:

  • A map of type `map[K][]T`, where each key is associated with a slice of elements that share that key.

Example:

// Grouping integers by even and odd
numbers := []int{1, 2, 3, 4, 5}
grouped := GroupBy(numbers, func(n int) string {
	if n%2 == 0 {
		return "even"
	}
	return "odd"
})
// grouped will be map[string][]int{"even": {2, 4}, "odd": {1, 3, 5}}

// Grouping people by age
type Person struct {
    Name string
    Age  int
}
people := []Person{{Name: "Alice", Age: 30}, {Name: "Bob", Age: 25}, {Name: "Charlie", Age: 30}}
groupedByAge := GroupBy(people, func(p Person) int { return p.Age })
// groupedByAge will be map[int][]Person{30: {{Name: "Alice", Age: 30}, {Name: "Charlie", Age: 30}}, 25: {{Name: "Bob", Age: 25}}}

// Grouping strings by their length
words := []string{"apple", "pear", "banana", "peach"}
groupedByLength := GroupBy(words, func(word string) int { return len(word) })
// groupedByLength will be map[int][]string{5: {"apple", "peach"}, 4: {"pear"}, 6: {"banana"}}

func HasKey

func HasKey[K comparable, V any](m map[K]V, key K) bool

HasKey checks if a specified key is present within a given map.

This function takes a map with keys of any comparable type `K` and values of any type `V`. It checks if the specified `key` exists in the map `m`. If the key is found, it returns `true`; otherwise, it returns `false`.

The function is generic and can be used with maps that have keys of any type that supports comparison (e.g., int, string). The value type `V` can be any type.

Parameters:

  • `m`: The map in which to search for the key. The map has keys of type `K` and values of type `V`.
  • `key`: The key to search for within `m`. It should be of the same type `K` as the keys in `m`.

Returns:

  • `true` if `key` is found in `m`, `false` otherwise.

Example:

ages := map[string]int{"Alice": 30, "Bob": 25}
isPresent := HasKey(ages, "Alice") // isPresent will be true as "Alice" is a key in the map
prices := map[int]float64{1: 9.99, 2: 19.99}
isPresent := HasKey(prices, 3) // isPresent will be false as 3 is not a key in the map

func IndexExists

func IndexExists[T any](slice []T, index int) bool

IndexExists checks whether a given index is valid for the provided slice.

This function takes a slice `slice` of any type `T` and an integer `index`, and returns a boolean indicating whether the specified index is within the valid range for the slice. A valid index is one that is greater than or equal to 0 and less than the length of the slice.

Parameters:

  • `slice`: The input slice of any type `T` that is being checked.
  • `index`: The index to check for validity in the slice.

Returns:

  • `true` if the index is within the bounds of the slice (i.e., 0 <= index < len(slice)).
  • `false` otherwise, such as when the index is negative or greater than or equal to the length of the slice.

Example:

// Checking if an index exists in a slice
numbers := []int{1, 2, 3, 4}
exists := IndexExists(numbers, 2)
// exists will be true, as index 2 is valid for the slice

// Checking an invalid index
exists = IndexExists(numbers, 5)
// exists will be false, as index 5 is out of bounds for the slice

func IndexOf

func IndexOf[T comparable](slice []T, item T) int

IndexOf searches for a specific element in a slice and returns its index if found.

This function iterates over each element in the input slice `slice` to find the first occurrence of the specified `item`. If `item` is found, the function returns the index of `item` within `slice`. If `item` is not present in the slice, it returns -1.

The function is generic, allowing it to operate on slices of any comparable type `T` (e.g., int, string, or other types that support equality comparison).

Parameters:

  • `slice`: The slice in which to search for `item`. It can contain elements of any comparable type `T`.
  • `item`: The item to search for within `slice`. It should be of the same type `T` as the elements in `slice`.

Returns:

  • The zero-based index of `item` in `slice` if it exists; otherwise, -1.

Example:

// Searching for an integer in a slice
numbers := []int{1, 2, 3, 4}
index := IndexOf(numbers, 3)
// index will be 2, as 3 is located at index 2 in the slice

// Searching for a string in a slice
words := []string{"apple", "banana", "cherry"}
index = IndexOf(words, "banana")
// index will be 1, as "banana" is at index 1 in the slice

// Item not found in the slice
index = IndexOf(words, "date")
// index will be -1, as "date" is not in the slice

func Intersect

func Intersect[T comparable](slice1, slice2 []T) []T

Intersect returns a new slice containing elements that are present in both input slices.

This function takes two input slices, `slice1` and `slice2`, and identifies elements that are present in both slices. It uses a map to track the elements of `slice1`, then iterates over `slice2` to find common elements. If an element from `slice2` is found in the map (indicating it exists in `slice1`), it is added to the result slice.

The function is generic, allowing it to work with slices of any `comparable` type `T`.

Parameters:

  • `slice1`: The first input slice containing elements of any comparable type `T`.
  • `slice2`: The second input slice containing elements of any comparable type `T`.

Returns:

  • A new slice of type `[]T` that contains the elements found in both `slice1` and `slice2`. Each element in the result slice will appear only once, even if it is duplicated in the input slices.

Example:

// Finding common integers between two slices
numbers1 := []int{1, 2, 3, 4}
numbers2 := []int{3, 4, 5, 6}
commonNumbers := Intersect(numbers1, numbers2)
// commonNumbers will be []int{3, 4}

// Finding common strings between two slices
words1 := []string{"apple", "banana", "cherry"}
words2 := []string{"banana", "cherry", "date"}
commonWords := Intersect(words1, words2)
// commonWords will be []string{"banana", "cherry"}

// Intersecting with an empty slice results in an empty slice
empty := []int{}
intersectEmpty := Intersect(numbers1, empty)
// intersectEmpty will be []int{}

func InvertComp

func InvertComp[K, V comparable](m map[K]V) map[V]K

InvertComp inverts the keys and values of a map.

This function takes an input map `m` with keys of type `K` and values of type `V`, and creates a new map where the keys and values are swapped. It iterates over each key-value pair in the input map and adds an entry to the `result` map with the value as the key and the key as the value.

The function is generic, allowing it to work with maps where both the keys and values are of any comparable type.

Parameters:

  • `m`: The input map to be inverted, with keys of type `K` and values of type `V`.

Returns:

  • A new map of type `map[V]K`, where the keys and values from the input map `m` are swapped.

Example:

// Inverting a map with string keys and integer values
m := map[string]int{"a": 1, "b": 2, "c": 3}
inverted := InvertComp(m)
// inverted will be map[int]string{1: "a", 2: "b", 3: "c"}

func Join

func Join[T any](slice []T, separator string) string

Join concatenates the string representation of each element in a slice into a single string, with a specified separator between each element.

This function iterates over each element in the input slice `slice`, converts each element to a string using `fmt.Sprintf` with the `%v` format, and appends it to the `result` string. A separator string `separator` is inserted between elements in the final concatenated result. If the slice has only one element, no separator is added. The function is generic and can work with slices containing elements of any type `T`.

Parameters:

  • `slice`: The input slice containing elements to be joined. It can contain elements of any type `T`.
  • `separator`: A string that will be inserted between each element in the final result.

Returns:

  • A single string that is the result of concatenating all elements in `slice` with the specified `separator` in between.

Example:

// Joining integers with a comma separator
numbers := []int{1, 2, 3}
joinedNumbers := Join(numbers, ", ")
// joinedNumbers will be "1, 2, 3"

// Joining strings with a space separator
words := []string{"Go", "is", "awesome"}
joinedWords := Join(words, " ")
// joinedWords will be "Go is awesome"

// Joining an empty slice returns an empty string
emptySlice := []int{}
joinedEmpty := Join(emptySlice, ",")
// joinedEmpty will be ""

func JoinKeySep

func JoinKeySep[V any](m map[string]V, separator string) string

JoinKeySep concatenates the keys of a map into a single string, with each key separated by a specified separator.

This function takes a map `m` with string keys and any type of values `V`, and a `separator` string. It collects all the keys of the map into a slice, then joins them into a single string using the provided separator.

This function is generic, allowing it to work with maps that have values of any type `V`.

Parameters:

  • `m`: A map with string keys and values of any type `V`. Only the keys are used for concatenation.
  • `separator`: A string used to separate each key in the resulting string.

Returns:

  • A string containing all the keys in the map `m`, separated by the specified `separator`. If the map has no keys, an empty string is returned.

Example:

// Concatenating the keys of a map with a comma separator
m := map[string]int{"apple": 1, "banana": 2, "cherry": 3}
joinedKeys := JoinKeySep(m, ", ")
// joinedKeys will be "apple, banana, cherry"

// Using a different separator
m = map[string]bool{"cat": true, "dog": true}
joinedKeys = JoinKeySep(m, " | ")
// joinedKeys will be "cat | dog"

// With an empty map
emptyMap := map[string]int{}
joinedKeys = JoinKeySep(emptyMap, ",")
// joinedKeys will be ""

func KeyComp

func KeyComp[K comparable, V any](m map[K]V) []K

KeyComp returns all keys of a map.

This function takes a map `m` with keys of type `K` and values of type `V`, and creates a new slice containing all the keys from the map. The function iterates over the map and appends each key to the `keys` slice. The resulting slice will have the same number of elements as the map has key-value pairs, and the order of keys will correspond to the order in which they were iterated over (which is not guaranteed to be in any particular order).

The function is generic, allowing it to work with maps of any key type `K` and value type `V`.

Parameters:

  • `m`: The input map from which to extract the keys. The keys are of type `K`

Returns:

  • A slice of type `[]K` containing all the keys from the map `m`.

Example:

// Extracting keys from a map of strings to integers
map1 := map[string]int{"a": 1, "b": 2, "c": 3}
keys := KeyComp(map1)
// keys will be []string{"a", "b", "c"}

func Map

func Map[T any, U any](list []T, f func(T) U) []U

Map returns a new slice where each element is the result of applying a specified transformation function to each element in the input slice.

This function iterates over each element in the input slice `list`, applies the provided transformation function `f` to it, and stores the result in the new slice `result`. The length of the resulting slice is the same as the input slice, and each element in `result` corresponds to a transformed element from `list`.

The function is generic, allowing it to work with slices of any type `T` and apply a transformation function that converts each element of type `T` to a new type `U`.

Parameters:

  • `list`: The slice of elements to transform. It can contain elements of any type `T`.
  • `f`: A function that defines the transformation. It takes an element of type `T` as input and returns a transformed value of type `U`.

Returns:

  • A new slice of type `[]U` where each element is the result of applying `f` to the corresponding element in `list`.

Example:

numbers := []int{1, 2, 3, 4, 5}
squaredNumbers := Map(numbers, func(n int) int { return n * n })
// squaredNumbers will be []int{1, 4, 9, 16, 25} as each number is squared

words := []string{"apple", "banana", "cherry"}
wordLengths := Map(words, func(word string) int { return len(word) })
// wordLengths will be []int{5, 6, 6} as each word's length is calculated

func Merge

func Merge[K any, V any](maps ...map[any]V) map[any]V

Merge combines multiple maps into a single map. If there are any key conflicts, the value from the last map will be used.

This function accepts a variable number of maps of type `map[interface{}]V` and merges them into a single map. It iterates through each input map, adding all key-value pairs to the `mergedMap`. If a key already exists in `mergedMap`, the corresponding value from the current map will overwrite the existing value. The function returns the merged map.

The function is generic, allowing it to work with maps where the key is of any type `K` and the value is of any type `V`. It uses `interface{}` as the key type, enabling it to handle a variety of key types, though this may require careful handling of the key types to ensure they are comparable if needed.

Parameters:

  • `maps`: A variadic parameter representing multiple maps to be merged. Each map has keys of type `interface{}` and values of type `V`.

Returns:

  • A new map of type `map[interface{}]V` containing the merged key-value pairs. If there are key conflicts, the last map's value will be used.

Example:

// Merging two maps with integer keys and string values
map1 := map[interface{}]string{"a": "apple", "b": "banana"}
map2 := map[interface{}]string{"b": "blueberry", "c": "cherry"}
merged := Merge(map1, map2)
// merged will be map[interface{}]string{"a": "apple", "b": "blueberry", "c": "cherry"}

// Merging maps with different value types (e.g., int and string)
map3 := map[interface{}]int{"x": 10, "y": 20}
map4 := map[interface{}]string{"y": "yellow", "z": "zebra"}
mergedMixed := Merge(map3, map4)
// mergedMixed will be map[interface{}]string{"x": "10", "y": "yellow", "z": "zebra"}

// Merging an empty slice of maps returns an empty map
mergedEmpty := Merge()
// mergedEmpty will be an empty map

func MergeComp

func MergeComp[K comparable, V any](maps ...map[K]V) map[K]V

MergeComp merges multiple maps into a new map. Later maps override earlier ones for duplicate keys.

This function takes a variable number of maps with keys of type `K` and values of type `V`, and merges them into a single resulting map. It iterates through each input map, adding all key-value pairs to the `result` map. If a key already exists in `result`, the corresponding value from the current map will overwrite the existing value.

The function is generic, allowing it to work with maps where the keys are of any comparable type `K` and the values are of any type `V`.

Parameters:

  • `maps`: A variadic parameter representing multiple maps to be merged. Each map has keys of type `K` and values of type `V`.

Returns:

  • A new map of type `map[K]V` containing the merged key-value pairs. If there are

    key conflicts, the last map's value will be used.

Example:

// Merging two maps with string keys and integer values
map1 := map[string]int{"a": 1, "b": 2}
map2 := map[string]int{"b": 3, "c": 4}
merged := MergeComp(map1, map2)
// merged will be map[string]int{"a": 1, "b": 3, "c": 4}

func OmitComp

func OmitComp[K comparable, V any](m map[K]V, keys ...K) map[K]V

OmitComp creates a new map by excluding specific keys from the input map.

This function takes an input map `m` with keys of type `K` and values of type `V`, along with a variadic list of keys to exclude. It first constructs a set of keys to omit, then iterates over the input map and adds key-value pairs to the `result` map only if the key is not in the omit set. The function returns a new map containing only the key-value pairs that are not excluded.

The function is generic, allowing it to work with maps where the keys are of any comparable type `K` and the values are of any type `V`.

Parameters:

  • `m`: The input map from which to exclude key-value pairs. It has keys of type `K` and values of type `V`.
  • `keys`: A variadic parameter representing the keys to exclude from the input map.

Returns:

  • A new map of type `map[K]V` containing only the key-value pairs that are not excluded.

Example:

// Excluding specific keys from a map with string keys and integer values
m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}
omitted := OmitComp(m, "b", "d")
// omitted will be map[string]int{"a": 1, "c": 3}

func PickComp

func PickComp[K comparable, V any](m map[K]V, keys ...K) map[K]V

PickComp creates a new map by selecting specific keys from the input map.

This function takes an input map `m` with keys of type `K` and values of type `V`, along with a variadic list of keys to select. It iterates over the provided keys and checks if each key exists in the input map. If a key is found, it adds the corresponding key-value pair to the `result` map. The function returns a new map containing only the selected key-value pairs.

The function is generic, allowing it to work with maps where the keys are of any comparable type `K` and the values are of any type `V`.

Parameters:

  • `m`: The input map from which to select key-value pairs. It has keys of type `K` and values of type `V`.
  • `keys`: A variadic parameter representing the keys to select from the input map.

Returns:

  • A new map of type `map[K]V` containing only the key-value pairs for the specified keys.

Example:

// Selecting specific keys from a map with string keys and integer values
m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}
selected := PickComp(m, "b", "d")
// selected will be map[string]int{"b": 2, "d": 4}

func Pop

func Pop[T any](slice []T) []T

Pop removes the last element from a slice and returns the resulting slice.

This function takes an input slice `slice` and removes its last element by creating a new slice that excludes the last element. The function uses slicing to return a portion of the original slice that ends before the last element. If the input slice is empty, calling this function will result in a runtime panic.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice from which the last element will be removed. It can contain elements of any type `T`.

Returns:

  • A new slice of type `[]T`, containing all elements from the original slice except the last one.

Example:

// Removing the last element from a slice of integers
numbers := []int{1, 2, 3, 4}
updatedNumbers := Pop(numbers)
// updatedNumbers will be []int{1, 2, 3}

// Removing the last element from a slice of strings
words := []string{"apple", "banana", "cherry"}
updatedWords := Pop(words)
// updatedWords will be []string{"apple", "banana"}

// Attempting to pop from an empty slice will cause a runtime panic
var emptySlice []int
// updatedEmpty := Pop(emptySlice) // This will panic

func Push

func Push[T any](slice []T, element T) []T

Push appends an element to the end of a slice and returns the resulting slice.

This function takes an input slice `slice` and an element `element`, and appends the element to the end of the slice using the built-in `append` function. The function returns a new slice containing the original elements followed by the new element. This function is useful for adding elements dynamically to a slice.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice to which the element will be appended. It can contain elements of any type `T`.
  • `element`: The element to be appended to the end of the slice. It is of type `T`.

Returns:

  • A new slice of type `[]T`, containing the original elements in `slice` with `element` appended at the end.

Example:

// Appending an integer to a slice of integers
numbers := []int{1, 2, 3}
updatedNumbers := Push(numbers, 4)
// updatedNumbers will be []int{1, 2, 3, 4}

// Appending a string to a slice of strings
words := []string{"apple", "banana"}
updatedWords := Push(words, "cherry")
// updatedWords will be []string{"apple", "banana", "cherry"}

// Appending to an empty slice
var emptySlice []int
newSlice := Push(emptySlice, 1)
// newSlice will be []int{1}

func Reduce

func Reduce[T any, U any](slice []T, accumulator func(U, T) U, initialValue U) U

Reduce applies an accumulator function over a slice, producing a single accumulated result.

This function iterates over each element in the input slice `slice`, applying the `accumulator` function to combine each element with an accumulated result. It starts with an initial value `initialValue` and successively updates the result by applying `accumulator` to each element in `slice`. The final accumulated result is returned once all elements have been processed.

The function is generic, allowing it to operate on slices of any type `T` and produce an output of any type `U`. This enables flexible aggregation operations such as summing, counting, or accumulating data into more complex structures.

Parameters:

  • `slice`: The slice of elements to reduce. It can contain elements of any type `T`.
  • `accumulator`: A function that takes the current accumulated result of type `U` and an element of type `T`, then returns the updated accumulated result of type `U`.
  • `initialValue`: The initial value for the accumulator, of type `U`. This is the starting point for the reduction process.

Returns:

  • The final accumulated result of type `U` after applying `accumulator` to each element in `slice`.

Example:

// Summing integer values in a slice
numbers := []int{1, 2, 3, 4}
sum := Reduce(numbers, func(acc, n int) int { return acc + n }, 0)
// sum will be 10 as each integer is added to the accumulated result

// Concatenating strings in a slice
words := []string{"go", "is", "fun"}
sentence := Reduce(words, func(acc, word string) string { return acc + " " + word }, "")
// sentence will be " go is fun" (note leading space due to initial value being "")

// Using a custom struct and custom accumulator
type Product struct {
    Name  string
    Price float64
}
products := []Product{{Name: "apple", Price: 0.99}, {Name: "banana", Price: 1.29}}
totalPrice := Reduce(products, func(total float64, p Product) float64 { return total + p.Price }, 0.0)
// totalPrice will be 2.28 as each product's price is added to the accumulated total

func ReverseN

func ReverseN[T any](slice []T) []T

ReverseN reverses the order of elements in the input slice and returns a new slice containing the elements in reverse order.

This function creates a new slice `reversed` with the same length as the input slice `slice`. It then uses a two-pointer approach to swap the elements of `slice` from both ends toward the center, effectively reversing the slice. The result is a new slice with elements in the opposite order.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice whose elements are to be reversed. It can contain elements of any type `T`.

Returns:

  • A new slice of type `[]T` containing the elements of `slice` in reverse order.

Example:

// Reversing a slice of integers
numbers := []int{1, 2, 3, 4}
reversedNumbers := ReverseN(numbers)
// reversedNumbers will be []int{4, 3, 2, 1}

// Reversing a slice of strings
words := []string{"apple", "banana", "cherry"}
reversedWords := ReverseN(words)
// reversedWords will be []string{"cherry", "banana", "apple"}

// Reversing an empty slice returns an empty slice
empty := []int{}
reversedEmpty := ReverseN(empty)
// reversedEmpty will be []int{}

func Shift

func Shift[T any](slice []T) []T

Shift removes the first element from a slice and returns the resulting slice.

This function takes an input slice `slice` and removes its first element by creating a new slice that starts from the second element of the original slice. The function achieves this using slicing, effectively returning a view of the original slice that excludes the first element. If the input slice is empty, calling this function will result in a runtime panic due to out-of-bounds access.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice from which the first element will be removed. It can contain elements of any type `T`.

Returns:

  • A new slice of type `[]T`, containing all elements from the original slice except the first one.

Example:

// Removing the first element from a slice of integers
numbers := []int{1, 2, 3, 4}
updatedNumbers := Shift(numbers)
// updatedNumbers will be []int{2, 3, 4}

// Removing the first element from a slice of strings
words := []string{"apple", "banana", "cherry"}
updatedWords := Shift(words)
// updatedWords will be []string{"banana", "cherry"}

func Shuffle

func Shuffle[T any](slice []T) []T

Shuffle randomly shuffles the elements of a slice and returns a new slice with the shuffled elements.

This function takes an input slice `slice` and shuffles its elements using a random permutation. It creates a new slice `shuffledSlice` and populates it by selecting elements from the original slice according to a random permutation of indices. The resulting `shuffledSlice` contains the same elements as the input slice, but in a random order. The function uses a seeded random generator to ensure different results each time it is called.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice to be shuffled. It can contain elements of any type `T`.

Returns:

  • A new slice of type `[]T`, containing the shuffled elements of the input slice.

Example:

// Shuffling a slice of integers
numbers := []int{1, 2, 3, 4, 5}
shuffledNumbers := Shuffle(numbers)
// shuffledNumbers will be a random permutation of [1, 2, 3, 4, 5]

// Shuffling a slice of strings
words := []string{"apple", "banana", "cherry"}
shuffledWords := Shuffle(words)
// shuffledWords will be a random permutation of ["apple", "banana", "cherry"]

// Shuffling an empty slice returns an empty slice
empty := []int{}
shuffledEmpty := Shuffle(empty)
// shuffledEmpty will be []int{}

func Sort

func Sort[T any](slice []T, comparer func(T, T) bool) []T

Sort sorts a slice based on a custom comparison function and returns a new sorted slice.

This function takes an input slice `slice` and a comparison function `comparer` that defines the sorting order. The comparison function takes two elements of type `T` and returns `true` if the first element should come before the second one (i.e., if it should be sorted earlier). The function creates a new slice `sortedSlice` by copying the elements of the original slice, then sorts it in place using the provided `comparer`. The resulting `sortedSlice` will be a new slice containing the elements from the original slice, arranged in the order specified by the comparison function.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice to be sorted. It can contain elements of any type `T`.
  • `comparer`: A comparison function that takes two elements of type `T` and returns a boolean value. It determines the order of the elements: it should return `true` if the first element should come before the second element in the sorted order.

Returns:

  • A new slice of type `[]T`, containing the elements from the original slice sorted according to the provided comparison function.

Example:

// Sorting a slice of integers in ascending order
numbers := []int{5, 3, 8, 1, 2}
sortedNumbers := Sort(numbers, func(a, b int) bool {
	return a < b
})
// sortedNumbers will be []int{1, 2, 3, 5, 8}

// Sorting a slice of strings in descending order
words := []string{"apple", "banana", "cherry"}
sortedWords := Sort(words, func(a, b string) bool {
	return a > b
})
// sortedWords will be []string{"cherry", "banana", "apple"}

// Sorting an empty slice returns an empty slice
empty := []int{}
sortedEmpty := Sort(empty, func(a, b int) bool {
	return a < b
})
// sortedEmpty will be []int{}

func Sum

func Sum[T any](slice []T, transformer func(T) float64) float64

Sum calculates the sum of elements in a slice after transforming each element to a float64.

This function iterates over each element in the input slice `slice`, applies a transformation function `transformer` to convert the element to a float64, and adds the result to a running total. The final sum is returned as a float64.

The function is generic, allowing it to operate on slices of any type `T`. The `transformer` function is used to convert each element to a float64, enabling flexible summation of different types (e.g., integers, custom types with numeric properties).

Parameters:

  • `slice`: The slice of elements to sum. It can contain elements of any type `T`.
  • `transformer`: A function that takes an element of type `T` and returns a float64 representation, which will be used in the summation.

Returns:

  • A float64 representing the sum of the transformed elements.

Example:

// Summing integer slice values
numbers := []int{1, 2, 3, 4}
total := Sum(numbers, func(n int) float64 { return float64(n) })
// total will be 10.0 as each integer is converted to float64 and summed

// Summing custom struct values
type Product struct {
    Price float64
}
products := []Product{{Price: 9.99}, {Price: 19.99}, {Price: 5.0}}
totalPrice := Sum(products, func(p Product) float64 { return p.Price })
// totalPrice will be 34.98 as the prices are summed

func ToMap

func ToMap[T any, K comparable](slice []T, keyFunc func(T) K) map[K]T

ToMap converts a slice into a map, using a specified function to generate keys for each element in the slice.

This function iterates over each element in the input slice `slice`, applies the provided `keyFunc` function to generate a key for each element, and then inserts the element into the resulting map `result` using that key. This allows the creation of a map from a slice, where each element is accessible via a unique key.

The function is generic, allowing it to operate on slices of any type `T` and generate keys of any comparable type `K`. The resulting map will have keys of type `K` and values of type `T`.

Parameters:

  • `slice`: The slice of elements to convert to a map. It can contain elements of any type `T`.
  • `keyFunc`: A function that takes an element of type `T` and returns a key of type `K`, which is used as the key for each element in the resulting map.

Returns:

  • A map of type `map[K]T`, where each element in `slice` is inserted using the key generated by `keyFunc`. If `keyFunc` generates the same key for multiple elements, the last one will overwrite the previous entry in the map.

Example:

// Converting a slice of strings to a map with string lengths as keys
words := []string{"apple", "banana", "cherry"}
wordMap := ToMap(words, func(word string) int { return len(word) })
// wordMap will be map[int]string{5: "apple", 6: "cherry"}
// Note: "banana" is overwritten by "cherry" as they have the same key 6

// Converting a slice of structs to a map using a struct field as the key
type Person struct {
    ID   int
    Name string
}
people := []Person{{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}}
personMap := ToMap(people, func(p Person) int { return p.ID })
// personMap will be map[int]Person{1: {ID: 1, Name: "Alice"}, 2: {ID: 2, Name: "Bob"}}

func ToSlice

func ToSlice[T any, U any](slice []T, mapper func(T) U) []U

ToSlice applies a mapping function to each element in the input slice and returns a new slice containing the results of the mapping.

This function iterates over each element in the input slice `slice` and applies the provided `mapper` function to each element. The result of applying the mapping function to each element is stored in a new slice `mappedSlice`. This allows for transforming the elements of the input slice into a new slice of a different type.

The function is generic, allowing it to work with slices of any type `T` as input, and the result can be a slice of any type `U`.

Parameters:

  • `slice`: The input slice containing elements of type `T` to be mapped.
  • `mapper`: A function that takes an element of type `T` and returns a transformed element of type `U`.

Returns:

  • A new slice of type `[]U` containing the mapped elements, with the same length as the input slice, but with elements transformed according to the `mapper` function.

Example:

// Mapping a slice of integers to their string representations
numbers := []int{1, 2, 3}
mappedStrings := ToSlice(numbers, func(n int) string {
	return fmt.Sprintf("Number %d", n)
})
// mappedStrings will be []string{"Number 1", "Number 2", "Number 3"}

// Mapping a slice of strings to their lengths
words := []string{"apple", "banana", "cherry"}
mappedLengths := ToSlice(words, func(word string) int {
	return len(word)
})
// mappedLengths will be []int{5, 6, 6}

// Mapping an empty slice returns an empty slice
empty := []int{}
mappedEmpty := ToSlice(empty, func(n int) string {
	return fmt.Sprintf("Number %d", n)
})
// mappedEmpty will be []string{}

func UnflattenMap

func UnflattenMap(m map[string]any, prefix string) map[string]any

UnflattenMap converts a flat map with dot-separated keys into a nested map structure.

This function takes a flat map `m` where the keys are strings that may contain dot (".") separators, indicating a nested structure. It reconstructs the nested map by splitting the keys at each dot and creating nested maps accordingly.

The function returns a new map where the keys are organized into nested maps based of the original flat map.

Parameters:

  • `m`: The flat map to be unflattened. It has string keys and values of type `any`.
  • `prefix`: A string prefix to be removed from the keys before processing. This is typically an empty string when the function is called initially.

Returns:

  • A new map of type `map[string]any`, where the keys from the input map `m` are organized into a nested structure based on the dot-separated keys.

Example:

flatMap := map[string]any{
	"user.name": "Alice",
	"user.address.city": "Wonderland",
	"user.address.zip": "12345",
	"age": 30,
}
unflattened := UnflattenMap(flatMap, "")
// unflattened will be:
// map[string]any{
//		"user": map[string]any{
//			"name": "Alice",
//			"address": map[string]any{
//				"city": "Wonderland",
//				"zip": "12345",
//			},
//		},
//		"age": 30,
// }

func Unique

func Unique[T comparable](slice []T) []T

Unique returns a new slice containing only the unique elements from the input slice, preserving their original order.

This function iterates over each element in the input slice `slice` and uses a map `uniqueMap` to track elements that have already been encountered. If an element has not been seen before, it is added to both the `uniqueValues` result slice and the map. This ensures that only the first occurrence of each unique element is kept in the final slice, while duplicates are ignored.

The function is generic, allowing it to operate on slices of any comparable type `T`. The elements must be of a comparable type to allow them to be used as keys in the map.

Parameters:

  • `slice`: The input slice from which unique elements are extracted. It can contain elements of any comparable type `T`.

Returns:

  • A new slice of type `[]T` containing only the unique elements from `slice` in the order of their first appearance.

Example:

// Extracting unique integers from a slice
numbers := []int{1, 2, 2, 3, 4, 4, 5}
uniqueNumbers := Unique(numbers)
// uniqueNumbers will be []int{1, 2, 3, 4, 5}

// Extracting unique strings from a slice
words := []string{"apple", "banana", "apple", "cherry"}
uniqueWords := Unique(words)
// uniqueWords will be []string{"apple", "banana", "cherry"}

// An empty slice will return an empty result
empty := []int{}
uniqueEmpty := Unique(empty)
// uniqueEmpty will be []int{}

func Unshift

func Unshift[T any](slice []T, element T) []T

Unshift inserts an element at the beginning of a slice and returns the resulting slice.

This function takes an input slice `slice` and an element `element`, then creates a new slice by appending the `element` at the start, followed by the elements of the original slice. The function uses the built-in `append` function to combine a new slice containing just the `element` with the original slice, effectively adding the element to the beginning.

The function is generic, allowing it to work with slices of any type `T`.

Parameters:

  • `slice`: The input slice to which the element will be prepended. It can contain elements of any type `T`.
  • `element`: The element to be inserted at the beginning of the slice. It is of type `T`.

Returns:

  • A new slice of type `[]T`, containing `element` followed by all the elements of the original `slice`.

Example:

// Adding an integer to the beginning of a slice of integers
numbers := []int{2, 3, 4}
updatedNumbers := Unshift(numbers, 1)
// updatedNumbers will be []int{1, 2, 3, 4}

// Adding a string to the beginning of a slice of strings
words := []string{"banana", "cherry"}
updatedWords := Unshift(words, "apple")
// updatedWords will be []string{"apple", "banana", "cherry"}

// Adding to an empty slice
var emptySlice []int
newSlice := Unshift(emptySlice, 1)
// newSlice will be []int{1}

func Values

func Values[K any, V any](m map[any]V) []V

Values extracts and returns the values from a map as a slice.

This function takes a map `m` with keys of type `any` and values of type `V`, and creates a new slice containing all the values from the map. The function iterates over the map and appends each value to the `values` slice. The resulting slice will have the same number of elements as the map has key-value pairs, and the order of values will correspond to the order in which they were iterated over (which is not guaranteed to be in any particular order).

The function is generic, allowing it to work with maps of any key type `K` and value type `V`.

Parameters:

  • `m`: The input map from which to extract the values. The keys are of type `any` and the values are of type `V`.

Returns:

  • A slice of type `[]V` containing all the values from the map `m`.

Example:

// Extracting values from a map of strings to integers
map1 := map[any]int{"a": 1, "b": 2, "c": 3}
values := Values(map1)
// values will be []int{1, 2, 3}

// Extracting values from a map of strings to strings
map2 := map[any]string{"x": "apple", "y": "banana", "z": "cherry"}
valuesStrings := Values(map2)
// valuesStrings will be []string{"apple", "banana", "cherry"}

// Extracting values from an empty map returns an empty slice
emptyMap := map[any]int{}
emptyValues := Values(emptyMap)
// emptyValues will be []int{}

func ValuesComp

func ValuesComp[K comparable, V, U any](m map[K]V, fn func(V) U) map[K]U

ValuesComp applies a transformation function to each value in a map and returns a new map with the same keys and transformed values.

This function iterates over each key-value pair in the input map `m`, applies the provided transformation function `fn` to each value, and stores the result in a new map `result`. The keys in the resulting map remain the same as in the input map, while the values are transformed according to the function `fn`.

The function is generic, allowing it to work with maps where the keys are of any comparable type `K`, the original values are of type `V`, and the transformed values are of type `U`.

Parameters:

  • `m`: The input map with keys of type `K` and values of type `V`.
  • `fn`: A function that takes a value of type `V` and returns a transformed value of type `U`.

Returns:

  • A new map of type `map[K]U`, where each value is the result of applying `fn` to the corresponding value in the input map `m`.

Example:

// Transforming a map of integers to their string representations
m := map[string]int{"one": 1, "two": 2, "three": 3}
transformed := ValuesComp(m, func(v int) string {
	return fmt.Sprintf("Number %d", v)
})
// transformed will be map[string]string{"one": "Number 1", "two": "Number 2", "three": "Number 3"}

Types

type HashMap

type HashMap[K, V comparable] struct {
	// contains filtered or unexported fields
}

HashMap is a generic hash map data structure that maps keys of type `K` to values of type `V`. `K` and `V` must be comparable types, meaning that they support comparison operators (like == and !=). The `items` field stores the actual map, which is used to store key-value pairs.

func NewHashMap

func NewHashMap[K, V comparable]() *HashMap[K, V]

NewHashMap is a constructor function that initializes and returns a pointer to a new, empty `HashMap`. It creates a new map with keys of type `K` and values of type `V`.

Generics are used to make this function flexible for any types of keys and values as long as they are comparable. The function ensures that the map is properly initialized before returning it.

Example usage:

hashMap := NewHashMap[string, int]() // Creates a HashMap with string keys and int values.

func (*HashMap[K, V]) Clear

func (hash *HashMap[K, V]) Clear()

Clear removes all key-value pairs from the HashMap, effectively resetting it to an empty map.

Example:

hashMap.Clear() // Clears the map, removing all entries.

func (*HashMap[K, V]) ContainsKey

func (hash *HashMap[K, V]) ContainsKey(key K) bool

ContainsKey checks whether the specified key exists in the HashMap. Parameters:

  • `key`: The key to check for existence in the map.

Returns:

  • `true` if the key exists in the map, `false` otherwise.

Example:

exists := hashMap.ContainsKey("apple") // Checks if the key "apple" exists in the map.

func (*HashMap[K, V]) Get

func (hash *HashMap[K, V]) Get(key K) (value V)

Get retrieves the value associated with the given key from the HashMap. If the key exists, it returns the corresponding value. If the key does not exist, it returns the zero value for the type `V`. Parameters:

  • `key`: The key whose associated value is to be returned.

Returns:

  • The value associated with the key, or the zero value for `V` if the key is not found.

Example:

value := hashMap.Get("apple") // Retrieves the value associated with "apple".

func (*HashMap[K, V]) IsEmpty

func (hash *HashMap[K, V]) IsEmpty() bool

IsEmpty checks if the HashMap is empty (i.e., contains no key-value pairs). Returns:

  • `true` if the map is empty, `false` otherwise.

Example:

isEmpty := hashMap.IsEmpty() // Returns true if the map is empty.

func (*HashMap[K, V]) KeySet

func (hash *HashMap[K, V]) KeySet() []K

KeySet returns a slice of all keys currently stored in the HashMap. Returns:

  • A slice containing all keys in the map.

Example:

keys := hashMap.KeySet() // Returns all the keys in the map.

func (*HashMap[K, V]) Put

func (hash *HashMap[K, V]) Put(key K, value V)

Put adds a new key-value pair to the HashMap. If the key already exists, its value is updated. Parameters:

  • `key`: The key to be added or updated in the map.
  • `value`: The value to be associated with the key.

Example:

hashMap.Put("apple", 5) // Inserts or updates the value of "apple" to 5.

func (*HashMap[K, V]) Remove

func (hash *HashMap[K, V]) Remove(key K)

Remove deletes the key-value pair from the HashMap for the specified key. If the key does not exist, no action is taken. Parameters:

  • `key`: The key to be removed from the map.

Example:

hashMap.Remove("apple") // Removes the "apple" key and its associated value.

func (*HashMap[K, V]) Size

func (hash *HashMap[K, V]) Size() int

Size returns the number of key-value pairs currently stored in the HashMap. Returns:

  • The number of key-value pairs in the map.

Example:

size := hashMap.Size() // Gets the size of the map.

type HashSet

type HashSet[T comparable] struct {
	// contains filtered or unexported fields
}

HashSet is a generic set data structure that stores unique elements of type `T`. It is implemented using a map where the keys are the elements and the values are empty structs (`struct{}`), which is an efficient way to represent a set in Go. The type `T` must be comparable, meaning it can be compared using == and !=.

func NewHashSet

func NewHashSet[T comparable](elements ...T) *HashSet[T]

NewHashSet is a constructor function that creates a new `HashSet` and optionally adds any provided elements to the set. Parameters:

  • `elements`: A variadic list of elements of type `T` to initialize the set with (optional).

Returns:

  • A pointer to the newly created `HashSet`.

Example usage:

hashSet := NewHashSet(1, 2, 3) // Creates a set with initial elements 1, 2, and 3.

func (*HashSet[T]) Add

func (hash *HashSet[T]) Add(element T)

Add inserts a new element into the HashSet. If the element already exists, no action is taken. Parameters:

  • `element`: The element to be added to the set.

Example usage:

hashSet.Add(4) // Adds the element 4 to the set.

func (*HashSet[T]) AddAll

func (hash *HashSet[T]) AddAll(elements ...T)

AddAll inserts multiple elements into the HashSet. If any element already exists, it is ignored. Parameters:

  • `elements`: A variadic list of elements of type `T` to add to the set.

Example usage:

hashSet.AddAll(4, 5, 6) // Adds elements 4, 5, and 6 to the set.

func (*HashSet[T]) Clear

func (hash *HashSet[T]) Clear()

Clear removes all elements from the HashSet, resetting it to an empty set.

Example usage:

hashSet.Clear() // Clears all elements from the set.

func (*HashSet[T]) Contains

func (hash *HashSet[T]) Contains(element T) bool

Contains checks whether the specified element exists in the HashSet. Parameters:

  • `element`: The element to check for existence in the set.

Returns:

  • `true` if the element is present in the set, `false` otherwise.

Example usage:

exists := hashSet.Contains(3) // Checks if element 3 is in the set.

func (*HashSet[T]) Difference

func (hash *HashSet[T]) Difference(another *HashSet[T]) *HashSet[T]

Difference returns a new HashSet containing the elements that are in the current set but not in another set. Parameters:

  • `another`: Another `HashSet` to compare against.

Returns:

  • A new `HashSet` containing the difference between the current set and the other set.

Example usage:

resultSet := hashSet.Difference(anotherSet) // Returns the difference between two sets.

func (*HashSet[T]) Intersection

func (hash *HashSet[T]) Intersection(another *HashSet[T]) *HashSet[T]

Intersection returns a new HashSet containing only the elements present in both the current set and another set. Parameters:

  • `another`: Another `HashSet` to find the intersection with.

Returns:

  • A new `HashSet` containing the intersection of the two sets.

Example usage:

resultSet := hashSet.Intersection(anotherSet) // Returns the intersection of two sets.

func (*HashSet[T]) IsEmpty

func (hash *HashSet[T]) IsEmpty() bool

IsEmpty checks if the HashSet contains any elements. Returns:

  • `true` if the set is empty, `false` otherwise.

Example usage:

isEmpty := hashSet.IsEmpty() // Returns true if the set is empty.

func (*HashSet[T]) Remove

func (hash *HashSet[T]) Remove(element T)

Remove deletes the specified element from the HashSet. If the element does not exist, no action is taken. Parameters:

  • `element`: The element to be removed from the set.

Example usage:

hashSet.Remove(5) // Removes element 5 from the set.

func (*HashSet[T]) RemoveAll

func (hash *HashSet[T]) RemoveAll(elements ...T)

RemoveAll deletes multiple elements from the HashSet. Parameters:

  • `elements`: A variadic list of elements to be removed from the set.

Example usage:

hashSet.RemoveAll(2, 4, 6) // Removes elements 2, 4, and 6 from the set.

func (*HashSet[T]) Size

func (hash *HashSet[T]) Size() int

Size returns the number of elements currently stored in the HashSet. Returns:

  • The number of elements in the set.

Example usage:

size := hashSet.Size() // Returns the size of the set.

func (*HashSet[T]) Slice

func (hash *HashSet[T]) Slice() []T

Slice converts the HashSet into a slice of elements. Returns:

  • A slice containing all elements in the set.

Example usage:

slice := hashSet.Slice() // Converts the set to a slice.

func (*HashSet[T]) String

func (hash *HashSet[T]) String() string

String returns a string representation of the HashSet, with elements separated by commas. Returns:

  • A string that represents the elements in the set.

Example usage:

str := hashSet.String() // Returns a string representation of the set.

func (*HashSet[T]) Union

func (hash *HashSet[T]) Union(another *HashSet[T]) *HashSet[T]

Union returns a new HashSet that contains all elements from both the current set and another set. Parameters:

  • `another`: Another `HashSet` to combine with the current set.

Returns:

  • A new `HashSet` containing the union of the two sets.

Example usage:

resultSet := hashSet.Union(anotherSet) // Returns the union of two sets.

type Stack

type Stack[T comparable] struct {
	// contains filtered or unexported fields
}

Stack is a generic stack data structure that stores elements of type `T`. It provides basic stack operations like push, pop, and peek. The type `T` must be comparable, allowing the stack to handle any type that supports equality comparison.

func NewStack

func NewStack[T comparable]() *Stack[T]

NewStack creates and returns a new, empty stack. Returns:

  • A pointer to an empty `Stack`.

Example usage:

stack := NewStack[int]() // Creates a new empty stack of integers.

func (*Stack[T]) Clear

func (stack *Stack[T]) Clear()

Clear removes all elements from the stack, leaving it empty.

Example usage:

stack.Clear() // Clears all elements from the stack.

func (*Stack[T]) IsEmpty

func (stack *Stack[T]) IsEmpty() bool

IsEmpty checks whether the stack contains any elements. Returns:

  • `true` if the stack is empty, `false` otherwise.

Example usage:

isEmpty := stack.IsEmpty() // Returns true if the stack is empty.

func (*Stack[T]) Peek

func (stack *Stack[T]) Peek() T

Peek returns the top element of the stack without removing it. If the stack is empty, it returns the zero value for type `T`. Returns:

  • The top element of the stack, or the zero value of `T` if the stack is empty.

Example usage:

top := stack.Peek() // Gets the top element of the stack without removing it.

func (*Stack[T]) Pop

func (stack *Stack[T]) Pop() T

Pop removes and returns the top element of the stack. If the stack is empty, it returns the zero value for type `T`. Returns:

  • The top element of the stack, or the zero value of `T` if the stack is empty.

Example usage:

top := stack.Pop() // Removes and returns the top element of the stack.

func (*Stack[T]) Push

func (stack *Stack[T]) Push(element T)

Push adds a new element to the top of the stack. Parameters:

  • `element`: The element to be added to the stack.

Example usage:

stack.Push(5) // Pushes the value 5 onto the stack.

func (*Stack[T]) Size

func (stack *Stack[T]) Size() int

Size returns the number of elements currently in the stack. Returns:

  • The number of elements in the stack.

Example usage:

size := stack.Size() // Returns the size of the stack.

Jump to

Keyboard shortcuts

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