arr

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2025 License: MIT Imports: 8 Imported by: 0

README

arr - Array and Slice Utility Functions for Go

The arr package provides a comprehensive set of utility functions for working with arrays, slices, maps, and sets in Go. It's inspired by libraries like Lodash for JavaScript and offers a wide range of functions to make working with collections easier and more expressive.

Installation

go get github.com/gflydev/utils/arr

Usage

import "github.com/gflydev/utils/arr"

Functions

Basic Array Operations
Chunk

Splits an array into chunks of the specified size. If the array can't be divided evenly, the last chunk will contain the remaining elements.

Parameters:

  • array: The array to split into chunks
  • size: The size of each chunk

Returns:

  • A new array containing chunks of the original array
result := arr.Chunk([]int{1, 2, 3, 4}, 2)
// result: [][]int{{1, 2}, {3, 4}}

result := arr.Chunk([]int{1, 2, 3, 4, 5}, 2)
// result: [][]int{{1, 2}, {3, 4}, {5}}

Note: If size is less than or equal to 0, an empty array will be returned.

Compact

Removes zero values from an array. In Go, we consider zero values (like 0 for integers, "" for strings) as falsey.

Parameters:

  • array: The array to compact

Returns:

  • A new array with all zero values removed
result := arr.Compact([]int{0, 1, 2, 0, 3})
// result: []int{1, 2, 3}

result := arr.Compact([]string{"", "a", "", "b"})
// result: []string{"a", "b"}
Contains

Checks if a slice contains a specific element. It returns true if the element is found, false otherwise.

// Check if a number exists in a slice
result := arr.Contains([]int{1, 2, 3, 4}, 3)
// result: true
result := arr.Contains([]int{1, 2, 3, 4}, 5)
// result: false

// Check if a string exists in a slice
result := arr.Contains([]string{"apple", "banana", "orange"}, "banana")
// result: true
result := arr.Contains([]string{"apple", "banana", "orange"}, "grape")
// result: false
Concat

Concatenates multiple arrays into a single array.

Parameters:

  • arrays: Variable number of arrays to concatenate

Returns:

  • A new array containing all elements from the input arrays
result := arr.Concat([]int{1, 2}, []int{3, 4})
// result: []int{1, 2, 3, 4}

result := arr.Concat([]string{"a", "b"}, []string{"c"}, []string{"d", "e"})
// result: []string{"a", "b", "c", "d", "e"}

Note: This function works with any type and preserves the order of elements from the input arrays.

Difference

Returns the elements in the first array that are not in the other arrays.

Parameters:

  • array: The base array to compare against
  • others: Variable number of arrays to compare with the base array

Returns:

  • A new array containing elements that are in the base array but not in any of the other arrays
result := arr.Difference([]int{1, 2, 3}, []int{2, 3, 4})
// result: []int{1}

result := arr.Difference([]string{"a", "b", "c"}, []string{"b"}, []string{"c", "d"})
// result: []string{"a"}

Note: This function requires elements to be comparable. It efficiently uses a map to track elements in the other arrays.

Drop

Creates a slice with n elements dropped from the beginning.

Parameters:

  • array: The input array
  • n: Number of elements to drop from the beginning

Returns:

  • A new array with the first n elements removed
result := arr.Drop([]int{1, 2, 3, 4}, 2)
// result: []int{3, 4}

result := arr.Drop([]string{"a", "b", "c"}, 1)
// result: []string{"b", "c"}

Note: If n is less than or equal to 0, the original array is returned. If n is greater than or equal to the length of the array, an empty array is returned.

DropRight

Creates a slice with n elements dropped from the end.

Parameters:

  • array: The input array
  • n: Number of elements to drop from the end

Returns:

  • A new array with the last n elements removed
result := arr.DropRight([]int{1, 2, 3, 4}, 2)
// result: []int{1, 2}

result := arr.DropRight([]string{"a", "b", "c"}, 1)
// result: []string{"a", "b"}

Note: If n is less than or equal to 0, the original array is returned. If n is greater than or equal to the length of the array, an empty array is returned.

Fill

Fills elements of an array with a value from start up to, but not including, end.

Parameters:

  • array: The input array
  • value: The value to fill the array with
  • start: The starting index (inclusive)
  • end: The ending index (exclusive)

Returns:

  • A new array with elements filled with the specified value
result := arr.Fill([]int{1, 2, 3, 4}, 0, 1, 3)
// result: []int{1, 0, 0, 4}

result := arr.Fill([]string{"a", "b", "c", "d"}, "x", 0, 2)
// result: []string{"x", "x", "c", "d"}

Note: If start is less than 0, it will be set to 0. If end is greater than the length of the array, it will be set to the length of the array. If start is greater than or equal to end, the original array is returned.

FindIndex

Returns the index of the first element that satisfies the provided testing function.

Parameters:

  • array: The input array
  • predicate: A function that returns true for elements that satisfy the condition

Returns:

  • The index of the first element that satisfies the predicate, or -1 if none found
result := arr.FindIndex([]int{1, 2, 3, 4}, func(n int) bool { return n > 2 })
// result: 2 (index of 3)

result := arr.FindIndex([]string{"a", "b", "c"}, func(s string) bool { return s == "b" })
// result: 1
FindLastIndex

Returns the index of the last element that satisfies the provided testing function.

Parameters:

  • array: The input array
  • predicate: A function that returns true for elements that satisfy the condition

Returns:

  • The index of the last element that satisfies the predicate, or -1 if none found
result := arr.FindLastIndex([]int{1, 3, 2, 3}, func(n int) bool { return n > 2 })
// result: 3 (index of the last 3)

result := arr.FindLastIndex([]string{"a", "b", "c", "b"}, func(s string) bool { return s == "b" })
// result: 3
First

Returns the first element of an array.

Parameters:

  • array: The input array

Returns:

  • The first element of the array
  • A boolean indicating whether the array is not empty (true if the array is not empty, false otherwise)
result, ok := arr.First([]int{1, 2, 3})
// result: 1, ok: true

result, ok := arr.First([]int{})
// result: 0, ok: false

result, ok := arr.First([]string{"a", "b"})
// result: "a", ok: true

Note: If the array is empty, the zero value of the element type and false are returned.

FirstOrDefault

Returns the first element of an array or a default value if the array is empty.

result := arr.FirstOrDefault([]int{1, 2, 3}, 0)
// result: 1

result := arr.FirstOrDefault([]int{}, 42)
// result: 42

// Works with any type
result := arr.FirstOrDefault([]string{"apple", "banana"}, "default")
// result: "apple"
result := arr.FirstOrDefault([]string{}, "default")
// result: "default"

// Works with structs
type User struct {
    Name string
}
users := []User{{Name: "Alice"}, {Name: "Bob"}}
defaultUser := User{Name: "Unknown"}
result := arr.FirstOrDefault(users, defaultUser)
// result: {Name: "Alice"}
result := arr.FirstOrDefault([]User{}, defaultUser)
// result: {Name: "Unknown"}
Flatten

Flattens a nested array into a single-level array.

Parameters:

  • array: The nested array to flatten

Returns:

  • A new array with all nested elements combined into a single level
// Flatten an array of integer arrays
result := arr.Flatten([][]int{{1, 2}, {3, 4}})
// result: []int{1, 2, 3, 4}

// Flatten an array of string arrays
result := arr.Flatten([][]string{{"a", "b"}, {"c"}})
// result: []string{"a", "b", "c"}

// Flatten an empty array
result := arr.Flatten([][]int{})
// result: []int{}

// Flatten an array with empty nested arrays
result := arr.Flatten([][]int{{}, {}, {}})
// result: []int{}

Note: This function efficiently pre-allocates memory for the result based on the total length of all nested arrays.

Includes

Checks if an array includes a certain value.

Parameters:

  • array: The array to search in
  • value: The value to search for

Returns:

  • bool: True if the value is found in the array, false otherwise
// Check if an integer exists in an array
result := arr.Includes([]int{1, 2, 3}, 2)
// result: true

// Check if a value is not in an array
result := arr.Includes([]int{1, 2, 3}, 4)
// result: false

// Works with strings
result := arr.Includes([]string{"a", "b", "c"}, "b")
// result: true

// Works with any comparable type
result := arr.Includes([]float64{1.1, 2.2, 3.3}, 2.2)
// result: true

Note: This function requires elements to be comparable. It performs a linear search through the array.

IndexOf

Returns the first index at which a given element can be found in the array.

Parameters:

  • array: The array to search in
  • value: The value to search for

Returns:

  • int: The index of the first occurrence of the value, or -1 if not found
// Find the index of a value in an integer array
result := arr.IndexOf([]int{1, 2, 3, 2}, 2)
// result: 1

// Find the index of a string in a string array
result := arr.IndexOf([]string{"a", "b", "c"}, "c")
// result: 2

// Return -1 when the value is not found
result := arr.IndexOf([]int{1, 2, 3}, 4)
// result: -1

Note: This function requires elements to be comparable. It performs a linear search through the array and returns the first matching index.

Initial

Gets all but the last element of an array.

Parameters:

  • array: The input array

Returns:

  • []T: A new array containing all elements except the last one
// Basic usage
result := arr.Initial([]int{1, 2, 3})
// result: []int{1, 2}

// With string array
result := arr.Initial([]string{"a", "b", "c"})
// result: []string{"a", "b"}

// With single element array
result := arr.Initial([]int{1})
// result: []int{} (empty array)

// With empty array
result := arr.Initial([]int{})
// result: []int{} (empty array)

Note: This function works with any type. If the input array has one or zero elements, an empty array is returned.

Intersection

Returns an array of unique values that are included in all given arrays.

Parameters:

  • arrays: Variable number of arrays to find common elements from

Returns:

  • []T: A new array containing elements that exist in all input arrays
// Basic usage with two arrays
result := arr.Intersection([]int{1, 2, 3}, []int{2, 3, 4})
// result: []int{2, 3}

// With multiple arrays
result := arr.Intersection([]string{"a", "b", "c"}, []string{"b", "c", "d"}, []string{"b", "e"})
// result: []string{"b"}

// With arrays that have no common elements
result := arr.Intersection([]int{1, 2}, []int{3, 4})
// result: []int{} (empty array)

// With a single array (returns unique values)
result := arr.Intersection([]int{1, 2, 2, 3})
// result: []int{1, 2, 3}

// With empty arrays
result := arr.Intersection([]int{}, []int{1, 2})
// result: []int{} (empty array)

Note: This function requires elements to be comparable. It efficiently handles multiple arrays and returns unique values that appear in all input arrays. If only one array is provided, it returns the unique values from that array.

Join

Joins all elements of an array into a string using a specified separator.

Parameters:

  • array: The array whose elements will be joined
  • separator: The string to insert between elements

Returns:

  • string: A string containing all array elements joined with the separator
// Join an array of integers
result := arr.Join([]int{1, 2, 3}, ", ")
// result: "1, 2, 3"

// Join an array of strings
result := arr.Join([]string{"a", "b", "c"}, "-")
// result: "a-b-c"

// Join an array of booleans
result := arr.Join([]bool{true, false}, " and ")
// result: "true and false"

// Join an empty array
result := arr.Join([]int{}, ",")
// result: ""

Note: This function works with any type. Elements are converted to strings using the str.ToString function, which provides proper string representation for various types.

Last

Returns the last element of an array.

Parameters:

  • array: The input array

Returns:

  • T: The last element of the array
  • bool: True if the array is not empty, false otherwise
// Basic usage
result, ok := arr.Last([]int{1, 2, 3})
// result: 3, ok: true

// With string array
result, ok := arr.Last([]string{"a", "b", "c"})
// result: "c", ok: true

// With empty array
result, ok := arr.Last([]int{})
// result: 0, ok: false (returns zero value of type T)

// With single element array
result, ok := arr.Last([]int{42})
// result: 42, ok: true

Note: This function works with any type. If the array is empty, it returns the zero value of type T and false. Otherwise, it returns the last element and true.

LastOrDefault

Returns the last element of an array or a default value if the array is empty. It safely handles empty arrays by returning the provided default value.

// Get the last element from a non-empty array
result := arr.LastOrDefault([]int{1, 2, 3}, 0)
// result: 3

// Get the default value from an empty array
result := arr.LastOrDefault([]int{}, 42)
// result: 42

// Works with any type
result := arr.LastOrDefault([]string{"apple", "banana"}, "default")
// result: "banana"
result := arr.LastOrDefault([]string{}, "default")
// result: "default"

// Works with structs
type User struct {
    Name string
}
users := []User{{Name: "Alice"}, {Name: "Bob"}}
defaultUser := User{Name: "Unknown"}
result := arr.LastOrDefault(users, defaultUser)
// result: {Name: "Bob"}
result := arr.LastOrDefault([]User{}, defaultUser)
// result: {Name: "Unknown"}
LastIndexOf

Returns the last index at which a given element can be found in the array.

Parameters:

  • array: The input array
  • value: The value to search for

Returns:

  • int: The index of the last occurrence of the value, or -1 if not found
// Basic usage
result := arr.LastIndexOf([]int{1, 2, 3, 2}, 2)
// result: 3 (index of the last occurrence of 2)

// With string array
result := arr.LastIndexOf([]string{"a", "b", "c", "b"}, "b")
// result: 3 (index of the last occurrence of "b")

// When value is not found
result := arr.LastIndexOf([]int{1, 2, 3}, 4)
// result: -1

// With empty array
result := arr.LastIndexOf([]int{}, 1)
// result: -1

Note: This function requires elements to be comparable. It performs a linear search through the array from the end to the beginning and returns the index of the first matching element found (which is the last occurrence in the original array).

Nth

Gets the element at index n of an array. If n is negative, it gets the element from the end.

Parameters:

  • array: The input array
  • n: The index of the element to retrieve

Returns:

  • The element at the specified index
  • A boolean indicating if a valid element was found
result, ok := arr.Nth([]int{1, 2, 3}, 1)
// result: 2, ok: true

result, ok := arr.Nth([]int{1, 2, 3}, -1)
// result: 3, ok: true (negative indices count from the end)

result, ok := arr.Nth([]int{1, 2, 3}, 5)
// result: 0, ok: false (index out of bounds)

result, ok := arr.Nth([]int{}, 0)
// result: 0, ok: false (empty array)
Pull

Removes all given values from an array.

Parameters:

  • array: The input array
  • values: Variable number of values to remove from the array

Returns:

  • A new array with all specified values removed
result := arr.Pull([]int{1, 2, 3, 1, 2, 3}, 2, 3)
// result: []int{1, 1}

result := arr.Pull([]string{"a", "b", "c", "a"}, "a")
// result: []string{"b", "c"}

result := arr.Pull([]int{1, 2, 3}, 4)
// result: []int{1, 2, 3} (no values removed)

Note: If the array or values are empty, the original array is returned.

Reverse

Reverses the order of elements in array.

Parameters:

  • slice: The input array to reverse

Returns:

  • A new array with elements in reverse order
result := arr.Reverse([]int{1, 2, 3})
// result: []int{3, 2, 1}

result := arr.Reverse([]string{"a", "b", "c"})
// result: []string{"c", "b", "a"}

result := arr.Reverse([]int{1})
// result: []int{1}
Shuffle

Returns a new slice with elements in random order.

Parameters:

  • slice: The input array to shuffle

Returns:

  • A new array with elements randomly reordered
result := arr.Shuffle([]int{1, 2, 3, 4, 5})
// result: [3, 1, 5, 2, 4] (elements will vary)

result := arr.Shuffle([]string{"a", "b", "c"})
// result: ["c", "a", "b"] (elements will vary)

Note: This function uses the Fisher-Yates shuffle algorithm to randomly reorder elements. It creates a copy of the original array, so the original array is not modified.

Random

Returns n random elements from the given slice without replacement.

  • If n <= 0 or the slice is empty, an empty slice is returned
  • If n >= len(slice), a shuffled copy of the entire slice is returned
  • The original slice is not modified
  • Uses the Shuffle function internally to randomize the elements
result := arr.Random([]int{1, 2, 3, 4, 5}, 3)
// result: []int{2, 4, 1} (elements will vary)

result := arr.Random([]string{"a", "b", "c", "d"}, 2)
// result: []string{"c", "a"} (elements will vary)

// If n >= len(slice), returns all elements in random order
result := arr.Random([]int{1, 2}, 3)
// result: []int{2, 1} (order will vary)
RandomChoice

Returns a randomly selected element from an array along with a boolean indicating success.

  • If the array is empty, returns the zero value of the type and false
  • If the array has only one element, returns that element and true
  • Otherwise, returns a randomly selected element and true
result, ok := arr.RandomChoice([]string{"a", "b", "c"})
// result: "b", ok: true (element will vary)

result, ok := arr.RandomChoice([]int{1, 2, 3, 4})
// result: 3, ok: true (element will vary)

result, ok := arr.RandomChoice([]int{})
// result: 0, ok: false
Slice

Creates a slice of array from start up to, but not including, end.

Parameters:

  • array: The input array
  • start: The starting index (inclusive)
  • end: The ending index (exclusive)

Returns:

  • A new array containing elements from start index up to but not including end index
result := arr.Slice([]int{1, 2, 3, 4}, 1, 3)
// result: []int{2, 3}

result := arr.Slice([]string{"a", "b", "c", "d"}, 0, 2)
// result: []string{"a", "b"}

result := arr.Slice([]int{1, 2, 3}, 2, 2)
// result: []int{}

Note: The function handles edge cases gracefully. If start is negative, it's set to 0. If end is greater than the array length, it's set to the array length. If start is greater than or equal to end, an empty array is returned.

SortedIndex

Returns the index at which a value should be inserted into a sorted array to maintain sort order.

result := arr.SortedIndex([]int{1, 3, 5, 7}, 4)
// result: 2

result := arr.SortedIndex([]int{10, 20, 30, 40}, 25)
// result: 2

result := arr.SortedIndex([]float64{1.5, 3.5, 5.5}, 0.5)
// result: 0
Tail

Returns all but the first element of array.

Parameters:

  • array: The input array

Returns:

  • A new array containing all elements except the first one
result := arr.Tail([]int{1, 2, 3})
// result: []int{2, 3}

result := arr.Tail([]string{"a", "b", "c"})
// result: []string{"b", "c"}

result := arr.Tail([]int{1})
// result: []int{}

Note: If the array has 0 or 1 elements, an empty array is returned.

Take

Creates a slice of array with n elements taken from the beginning.

Parameters:

  • array: The input array
  • n: Number of elements to take from the beginning

Returns:

  • A new array with the first n elements
result := arr.Take([]int{1, 2, 3, 4}, 2)
// result: []int{1, 2}

result := arr.Take([]string{"a", "b", "c"}, 1)
// result: []string{"a"}

result := arr.Take([]int{1, 2}, 3)
// result: []int{1, 2}

Note: If n is less than or equal to 0, an empty array is returned. If n is greater than or equal to the length of the array, the entire array is returned.

TakeRight

Creates a slice of array with n elements taken from the end.

Parameters:

  • array: The input array
  • n: Number of elements to take from the end

Returns:

  • A new array with the last n elements
result := arr.TakeRight([]int{1, 2, 3, 4}, 2)
// result: []int{3, 4}

result := arr.TakeRight([]string{"a", "b", "c"}, 1)
// result: []string{"c"}

result := arr.TakeRight([]int{1, 2}, 3)
// result: []int{1, 2}

Note: If n is less than or equal to 0, an empty array is returned. If n is greater than or equal to the length of the array, the entire array is returned.

Union

Creates an array of unique values from all given arrays.

Parameters:

  • arrays: Variable number of arrays to combine

Returns:

  • A new array containing all unique elements from the input arrays
result := arr.Union([]int{1, 2}, []int{2, 3})
// result: []int{1, 2, 3}

result := arr.Union([]string{"a", "b"}, []string{"b", "c"}, []string{"c", "d"})
// result: []string{"a", "b", "c", "d"}

result := arr.Union([]int{1, 1, 2}, []int{2, 2, 3})
// result: []int{1, 2, 3}
Uniq

Creates an array of unique values.

Parameters:

  • array: The input array

Returns:

  • A new array with duplicate elements removed
result := arr.Uniq([]int{1, 2, 2, 3})
// result: []int{1, 2, 3}

result := arr.Uniq([]string{"a", "b", "a", "c", "b"})
// result: []string{"a", "b", "c"}

result := arr.Uniq([]int{1, 1, 1})
// result: []int{1}
Unique

Removes duplicate elements from a slice, returning a new slice with only unique elements.

result := arr.Unique([]int{1, 2, 2, 3})
// result: []int{1, 2, 3}

// Works with any comparable type
result := arr.Unique([]string{"apple", "banana", "apple", "orange"})
// result: []string{"apple", "banana", "orange"}

// For structs, all fields must match for it to be considered a duplicate
type User struct {
    ID int
    Name string
}
users := []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
    {ID: 1, Name: "Alice"}, // Duplicate
    {ID: 3, Name: "Charlie"},
    {ID: 2, Name: "Bob"},   // Duplicate
}
uniqueUsers := arr.Unique(users)
// Returns [{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}, {ID: 3, Name: "Charlie"}]
Without

Returns an array excluding all given values.

Parameters:

  • array: The input array
  • values: Variable number of values to exclude from the array

Returns:

  • A new array with all specified values excluded
result := arr.Without([]int{1, 2, 3, 4}, 2, 3)
// result: []int{1, 4}

result := arr.Without([]string{"a", "b", "c"}, "a", "c")
// result: []string{"b"}

result := arr.Without([]int{1, 2, 3}, 4)
// result: []int{1, 2, 3}

Note: This function is implemented using the Pull function.

Collapse

Collapses a slice of slices into a single slice. It flattens a two-dimensional slice into a one-dimensional slice.

// Collapse multiple slices into one
Collapse([][]any{
    {1, 2, 3},
    {4, 5},
    {6, 7, 8, 9},
}) // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9]

// Collapse with mixed types
Collapse([][]any{
    {"a", "b"},
    {1, 2},
    {true, false},
}) // Returns ["a", "b", 1, 2, true, false]

// Collapse with empty slices
Collapse([][]any{
    {1, 2},
    {},
    {3, 4},
}) // Returns [1, 2, 3, 4]

// Collapse an empty slice
Collapse([][]any{}) // Returns []
CrossJoin

Cross joins the given arrays, returning a cartesian product with all possible permutations. It generates all possible combinations by taking one element from each input array.

// Cross join two arrays
CrossJoin([]int{1, 2}, []int{3, 4})
// Returns [[1, 3], [1, 4], [2, 3], [2, 4]]

// Cross join three arrays
CrossJoin([]string{"a", "b"}, []string{"c", "d"}, []string{"e", "f"})
// Returns [
//   ["a", "c", "e"], ["a", "c", "f"],
//   ["a", "d", "e"], ["a", "d", "f"],
//   ["b", "c", "e"], ["b", "c", "f"],
//   ["b", "d", "e"], ["b", "d", "f"]
// ]

// Cross join with a single array
CrossJoin([]int{1, 2, 3})
// Returns [[1], [2], [3]]

// Cross join with an empty array
CrossJoin([]int{}, []int{1, 2})
// Returns [] (empty result because one array is empty)

// Cross join with no arrays
CrossJoin[int]()
// Returns [] (empty result)
Zip

Zips multiple arrays together, creating a new array where each element is an array containing elements from the input arrays at the same index.

result := arr.Zip([]int{1, 2}, []int{3, 4})
// result: [][]int{{1, 3}, {2, 4}}

result := arr.Zip([]string{"a", "b"}, []string{"c", "d"}, []string{"e", "f"})
// result: [][]string{{"a", "c", "e"}, {"b", "d", "f"}}

result := arr.Zip([]int{1, 2, 3}, []int{4, 5})
// result: [][]int{{1, 4}, {2, 5}}
Accessible

Checks if a value is directly accessible as an array, slice, or map. Returns true if the value is an array, slice, or map; false otherwise.

// Check arrays, slices, and maps
result := arr.Accessible([]int{1, 2, 3}) // Returns true
result := arr.Accessible(map[string]int{"a": 1}) // Returns true
result := arr.Accessible([3]int{1, 2, 3}) // Returns true

// Check other types
result := arr.Accessible(42) // Returns false
result := arr.Accessible("hello") // Returns false
result := arr.Accessible(struct{}{}) // Returns false

// Check nil
result := arr.Accessible(nil) // Returns false

// Check pointers to arrays/slices/maps
arr := []int{1, 2, 3}
result := arr.Accessible(&arr) // Returns false (it's a pointer, not directly accessible)
Wrap

Ensures a value is contained in a slice. If the value is already a slice or array, it converts it to []any. Otherwise, it creates a new slice containing the value.

// Wrapping a single value
result := arr.Wrap(42)
// result: []any{42}

// Wrapping an existing slice
nums := []int{1, 2, 3}
result := arr.Wrap(nums)
// result: []any{1, 2, 3}

// Handling nil
result := arr.Wrap(nil)
// result: []any{} (empty slice)

// Wrapping a struct
type User struct {
    Name string
}
user := User{Name: "John"}
result := arr.Wrap(user)
// result: []any{User{Name: "John"}}
Functional Programming
Filter

Returns a new array with all elements that pass the test implemented by the provided function.

result := arr.Filter([]int{1, 2, 3, 4}, func(n int) bool { return n%2 == 0 })
// result: []int{2, 4}
WhereNotNull

Filters an array by removing nil values.

// Filter nil pointers from a slice
type User struct {
    Name string
}
var u1 = &User{Name: "Alice"}
var u2 *User = nil
var u3 = &User{Name: "Bob"}
users := []*User{u1, u2, u3}
result := arr.WhereNotNull(users)
// result: [&User{Name: "Alice"}, &User{Name: "Bob"}]

// Works with any type of nil values
values := []any{1, nil, "hello", nil, true}
result := arr.WhereNotNull(values)
// result: []any{1, "hello", true}
Find

Returns the first element in the array that satisfies the provided testing function and a boolean indicating whether such an element was found.

Parameters:

  • slice: The input slice to search in
  • predicate: A function that returns true for the element to find

Returns:

  • The first element for which the predicate returns true
  • A boolean indicating whether such an element was found (true if found, false otherwise)
// Find the first even number
result, ok := arr.Find([]int{1, 3, 4, 5, 6}, func(n int) bool { return n%2 == 0 })
// result: 4, ok: true

// Find a string with a specific prefix
result, ok := arr.Find([]string{"apple", "banana", "cherry"}, func(s string) bool {
    return strings.HasPrefix(s, "b")
})
// result: "banana", ok: true

// When no element is found
result, ok := arr.Find([]int{1, 3, 5}, func(n int) bool { return n%2 == 0 })
// result: 0 (zero value), ok: false
Map

Creates a new array with the results of calling a provided function on every element in the calling array.

Parameters:

  • slice: The input slice to transform
  • mapFunc: A function that transforms each element from type T to type R

Returns:

  • A new slice containing the transformed elements
// Double each number
result := arr.Map([]int{1, 2, 3}, func(n int) int { return n * 2 })
// result: []int{2, 4, 6}

// Convert integers to strings
result := arr.Map([]int{1, 2, 3}, func(n int) string { return fmt.Sprintf("Number %d", n) })
// result: []string{"Number 1", "Number 2", "Number 3"}

// Extract a field from structs
type User struct {
    ID int
    Name string
}
users := []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
    {ID: 3, Name: "Charlie"},
}
names := arr.Map(users, func(u User) string { return u.Name })
// Returns ["Alice", "Bob", "Charlie"]
Reduce

Applies a function against an accumulator and each element in the array to reduce it to a single value.

// Sum reducer
result := arr.Reduce([]int{1, 2, 3}, 0, func(acc, item int) int { return acc + item })
// result: 6

// Product reducer
result := arr.Reduce([]int{1, 2, 3}, 1, func(acc, item int) int { return acc * item })
// result: 6
SortBy

Sorts an array by the results of running each element through the iteratee function. It returns a new sorted array without modifying the original.

// Sort numbers in ascending order
result := arr.SortBy([]int{1, 3, 2}, func(n int) int { return n })
// result: []int{1, 2, 3}

// Sort strings by length
result := arr.SortBy([]string{"apple", "banana", "kiwi"}, func(s string) int { return len(s) })
// result: []string{"kiwi", "apple", "banana"}

// Sort structs by a specific field
type Person struct { Age int }
people := []Person{{Age: 30}, {Age: 25}, {Age: 40}}
result := arr.SortBy(people, func(p Person) int { return p.Age })
// result: []Person{{Age: 25}, {Age: 30}, {Age: 40}}
SortedCopy

Returns a sorted copy of the slice without modifying the original. It uses the provided less function to determine the order.

// Sort integers in ascending order
result := arr.SortedCopy([]int{3, 1, 4, 2}, func(i, j int) bool { return i < j })
// result: []int{1, 2, 3, 4}

// Sort integers in descending order
result := arr.SortedCopy([]int{3, 1, 4, 2}, func(i, j int) bool { return i > j })
// result: []int{4, 3, 2, 1}

// Sort strings by length
result := arr.SortedCopy([]string{"apple", "banana", "kiwi", "orange"}, func(i, j string) bool {
    return len(i) < len(j)
})
// result: []string{"kiwi", "apple", "orange", "banana"}

// Sort structs by a specific field
type Person struct {
    Name string
    Age int
}
people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 35},
}
// Sort by age
result := arr.SortedCopy(people, func(i, j Person) bool { return i.Age < j.Age })
// result: [{Name: "Bob", Age: 25}, {Name: "Alice", Age: 30}, {Name: "Charlie", Age: 35}]
GroupBy

Groups the elements of an array according to the result of calling the provided function on each element.

type Person struct {
    Name string
    Age  int
}

people := []Person{
    {"Alice", 25},
    {"Bob", 30},
    {"Charlie", 25},
    {"Dave", 30},
    {"Eve", 35},
}

// Group by age
result := arr.GroupBy(people, func(p Person) int { return p.Age })
// result: map[int][]Person{
//    25: {{"Alice", 25}, {"Charlie", 25}},
//    30: {{"Bob", 30}, {"Dave", 30}},
//    35: {{"Eve", 35}},
// }
KeyBy

Creates a map from an array, using the result of the key function as the map key. It transforms a slice into a map where each element is indexed by a key derived from the element itself.

// Key numbers by themselves
result := arr.KeyBy([]int{1, 2, 3}, func(n int) int { return n })
// Returns map[1:1 2:2 3:3]

// Key strings by their length
result := arr.KeyBy([]string{"apple", "banana", "kiwi"}, func(s string) int {
    return len(s)
})
// Returns map[5:"apple" 6:"banana" 4:"kiwi"]

// Key structs by a field
type User struct {
    ID int
    Name string
}
users := []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
    {ID: 3, Name: "Charlie"},
}
userMap := arr.KeyBy(users, func(u User) int { return u.ID })
// Returns map[1:{ID:1 Name:"Alice"} 2:{ID:2 Name:"Bob"} 3:{ID:3 Name:"Charlie"}]

// Note: If multiple elements produce the same key, later elements will overwrite earlier ones
Map Operations
MapMerge

Merges multiple maps into a single map.

m1 := map[string]int{"a": 1, "b": 2}
m2 := map[string]int{"b": 3, "c": 4}
result := arr.MapMerge(m1, m2)
// result: map[string]int{"a": 1, "b": 3, "c": 4}
Add

Adds a key/value pair to a map if the key doesn't already exist. It returns a new map without modifying the original.

// Add a new key/value pair
original := map[string]any{"name": "John", "age": 30}
result := arr.Add(original, "city", "New York")
// result = {"name": "John", "age": 30, "city": "New York"}
// original remains unchanged

// Try to add an existing key
original := map[string]any{"name": "John", "age": 30}
result := arr.Add(original, "name", "Jane")
// result = {"name": "John", "age": 30}
// The key "name" already exists, so the value is not changed

// Add to an empty map
empty := map[string]any{}
result := arr.Add(empty, "status", "active")
// result = {"status": "active"}
MapKeys

Extracts all keys from a map into a slice.

Parameters:

  • m: The source map

Returns:

  • A slice containing all keys from the map
data := map[string]int{"a": 1, "b": 2, "c": 3}
keys := arr.MapKeys(data)
// keys: []string{"a", "b", "c"} (order may vary)
MapValues

Extracts all values from a map into a slice.

Parameters:

  • m: The source map

Returns:

  • A slice containing all values from the map
data := map[string]int{"a": 1, "b": 2, "c": 3}
values := arr.MapValues(data)
// values: []int{1, 2, 3} (order may vary)
MapValuesFn

Transforms all values in a map using a mapping function.

Parameters:

  • m: The source map
  • mapFunc: A function that transforms values of type V to type R

Returns:

  • A new map with the same keys but transformed values
data := map[string]int{"a": 1, "b": 2, "c": 3}
doubled := arr.MapValuesFn(data, func(v int) int {
    return v * 2
})
// doubled: {"a": 2, "b": 4, "c": 6}

// Converting types
toString := arr.MapValuesFn(data, func(v int) string {
    return fmt.Sprintf("value-%d", v)
})
// toString: {"a": "value-1", "b": "value-2", "c": "value-3"}
MapFindKey

Finds the first key in a map that corresponds to a specific value.

Parameters:

  • m: The source map to search in
  • value: The value to search for

Returns:

  • The first key that maps to the specified value
  • A boolean indicating whether such a key was found
data := map[string]int{"a": 1, "b": 2, "c": 1}
key, found := arr.MapFindKey(data, 1)
// key: "a" (or "c" depending on map iteration order), found: true

key, found = arr.MapFindKey(data, 5)
// key: "" (zero value for string), found: false
MapToSlice

Converts a map to a slice of key-value pair structs.

data := map[string]int{"a": 1, "b": 2, "c": 3}
pairs := arr.MapToSlice(data)
// pairs is a slice of struct{Key string; Value int} with entries like:
// [{Key: "a", Value: 1}, {Key: "b", Value: 2}, {Key: "c", Value: 3}]
// (order may vary due to map iteration)

// You can iterate over the pairs:
for _, pair := range pairs {
    fmt.Printf("Key: %s, Value: %d\n", pair.Key, pair.Value)
}
MapSliceToMap

Converts a slice of key-value pair structs to a map. This is the inverse operation of MapToSlice.

pairs := []struct {
    Key   string
    Value int
}{
    {Key: "a", Value: 1},
    {Key: "b", Value: 2},
    {Key: "c", Value: 3},
}

data := arr.MapSliceToMap(pairs)
// data: map[string]int{"a": 1, "b": 2, "c": 3}

// If there are duplicate keys, the last one wins:
pairs2 := []struct {
    Key   string
    Value int
}{
    {Key: "a", Value: 1},
    {Key: "a", Value: 10},
}
data2 := arr.MapSliceToMap(pairs2)
// data2: map[string]int{"a": 10}
MapEqualMaps

Checks if two maps contain exactly the same key-value pairs.

map1 := map[string]int{"a": 1, "b": 2, "c": 3}
map2 := map[string]int{"c": 3, "b": 2, "a": 1} // Same content, different order
map3 := map[string]int{"a": 1, "b": 2}         // Missing a key
map4 := map[string]int{"a": 1, "b": 2, "c": 4} // Different value

arr.MapEqualMaps(map1, map2) // Returns: true
arr.MapEqualMaps(map1, map3) // Returns: false
arr.MapEqualMaps(map1, map4) // Returns: false
MapDiffMaps

Compares two maps and returns three maps containing the added, removed, and changed entries.

m1 := map[string]int{"a": 1, "b": 2, "c": 3}
m2 := map[string]int{"b": 2, "c": 4, "d": 5}
added, removed, changed := arr.MapDiffMaps(m1, m2)
// added: map[string]int{"d": 5}
// removed: map[string]int{"a": 1}
// changed: map[string]int{"c": 4}
Divide

Returns two slices, one containing the keys, and the other containing the values of the original map. It separates a map into its keys and values while preserving the corresponding order.

// Divide a map into keys and values
keys, values := arr.Divide(map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
})
// keys could be ["name", "age", "city"] (order may vary)
// values could be ["John", 30, "New York"] (in the same order as keys)

// Divide an empty map
keys, values := arr.Divide(map[string]any{})
// keys = [] (empty slice)
// values = [] (empty slice)

// Note: The order of keys and values is not guaranteed to be the same across different runs
// due to the non-deterministic iteration order of Go maps
Dot

Flattens a multi-dimensional map into a single level map with "dot" notation. It converts nested maps into a flat map where keys are paths to values using dot separators.

// Flatten a nested map
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
            "zip": 10001,
        },
    },
    "status": "active",
}

flat := arr.Dot(nested)
// Returns:
// {
//    "user.name": "John",
//    "user.address.city": "New York",
//    "user.address.zip": 10001,
//    "status": "active"
// }

// Flatten an empty map
arr.Dot(map[string]any{}) // Returns an empty map

// Flatten a map with no nested structures
arr.Dot(map[string]any{"a": 1, "b": 2}) // Returns the same map {"a": 1, "b": 2}
Undot

Converts a flattened map with dot notation keys into a nested map structure. It's the opposite operation of Dot.

// Convert a flat map to a nested structure
data := map[string]any{
    "user.name": "John",
    "user.address.city": "New York",
    "user.address.zip": "10001",
    "status": "active",
}

result := arr.Undot(data)
// Returns:
// {
//   "user": {
//     "name": "John",
//     "address": {
//       "city": "New York",
//       "zip": "10001"
//     }
//   },
//   "status": "active"
// }

// Handle an empty map
result := arr.Undot(map[string]any{})
// Returns an empty map

// Handle a map with no dot notation
data := map[string]any{"name": "John", "age": 30}
result := arr.Undot(data)
// Returns the same structure: {"name": "John", "age": 30}
Except

Creates a new map excluding the specified keys from the original map. It returns a copy of the map without the specified keys.

// Remove specific keys
original := map[string]any{"name": "John", "age": 30, "city": "New York"}
result := arr.Except(original, "age", "city")
// Returns {"name": "John"}

// Remove all keys
original := map[string]any{"a": 1, "b": 2}
result := arr.Except(original, "a", "b")
// Returns {} (empty map)

// No keys to remove
original := map[string]any{"a": 1, "b": 2}
result := arr.Except(original)
// Returns {"a": 1, "b": 2} (unchanged)
Exists

Checks if a given key exists in a map. It returns true if the key exists, false otherwise.

// Check if a key exists
user := map[string]any{
    "name": "John",
    "age": 30,
}
result := arr.Exists(user, "name") 
// Returns true
result := arr.Exists(user, "email") 
// Returns false

// Check in an empty map
result := arr.Exists(map[string]any{}, "key") 
// Returns false

// Check with a nil map
var nilMap map[string]any
result := arr.Exists(nilMap, "key") 
// Returns false (safe to use with nil maps)
Get

Retrieves a value from a map using dot notation for nested keys, with a default value if the key doesn't exist.

// Get values from a nested map
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
        },
    },
    "status": "active",
}

result := arr.Get(nested, "user.name", "Unknown")
// Returns "John"

result := arr.Get(nested, "user.address.city", "Unknown")
// Returns "New York"

result := arr.Get(nested, "user.address.country", "USA")
// Returns "USA" (key doesn't exist, so default value is returned)

result := arr.Get(nested, "user.email", nil)
// Returns nil (key doesn't exist, so default value is returned)

// Empty key returns the entire map
result := arr.Get(nested, "", nil)
// Returns the entire nested map
Has

Determines if all of the specified keys exist in the map using "dot" notation. It checks if every key in the provided list exists in the map, including nested keys. Returns true only if all keys exist.

// Check simple keys
data := map[string]any{
    "name": "John",
    "age": 30,
}
result := arr.Has(data, "name")
// Returns true

result := arr.Has(data, "email")
// Returns false

result := arr.Has(data, "name", "age")
// Returns true (both keys exist)

result := arr.Has(data, "name", "email")
// Returns false (not all keys exist)

// Check nested keys
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
        },
    },
}

result := arr.Has(nested, "user.name")
// Returns true

result := arr.Has(nested, "user.address.city")
// Returns true

result := arr.Has(nested, "user.address.country")
// Returns false

result := arr.Has(nested, "user.name", "user.address.city")
// Returns true (both keys exist)

// Empty keys list
result := arr.Has(data)
// Returns false (no keys to check)
HasAny

Determines if any of the specified keys exist in the map using "dot" notation. It checks if at least one key in the provided list exists in the map, including nested keys. Returns true if any key exists.

// Check simple keys
data := map[string]any{
    "name": "John",
    "age": 30,
}
result := arr.HasAny(data, "name")
// Returns true

result := arr.HasAny(data, "email")
// Returns false

result := arr.HasAny(data, "name", "email")
// Returns true (at least one key exists)

result := arr.HasAny(data, "email", "phone")
// Returns false (none of the keys exist)

// Check nested keys
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
        },
    },
}

result := arr.HasAny(nested, "user.name")
// Returns true

result := arr.HasAny(nested, "user.address.city")
// Returns true

result := arr.HasAny(nested, "user.address.country")
// Returns false

result := arr.HasAny(nested, "user.address.country", "user.name")
// Returns true (at least one key exists)

// Empty keys list
result := arr.HasAny(data)
// Returns false (no keys to check)
IsAssoc

Determines if a value is an associative array/map (has string keys). It checks if the value is a map with string keys.

// Check associative arrays (maps with string keys)
result := arr.IsAssoc(map[string]any{"name": "John", "age": 30})
// Returns true

result := arr.IsAssoc(map[string]int{"a": 1, "b": 2})
// Returns true

// Check non-associative arrays
result := arr.IsAssoc([]int{1, 2, 3})
// Returns false (slice, not a map)

result := arr.IsAssoc(map[int]string{1: "a", 2: "b"})
// Returns false (map with non-string keys)

// Check other types
result := arr.IsAssoc(42)
// Returns false

result := arr.IsAssoc("hello")
// Returns false

// Check nil
result := arr.IsAssoc(nil)
// Returns false
IsList

Determines if a value is a list (array or slice). It checks if the value is an array or slice type.

// Check list types
result := arr.IsList([]int{1, 2, 3})
// Returns true (slice)

result := arr.IsList([3]string{"a", "b", "c"})
// Returns true (array)

// Check non-list types
result := arr.IsList(map[string]int{"a": 1, "b": 2})
// Returns false (map, not a slice/array)

result := arr.IsList(42)
// Returns false

result := arr.IsList("hello")
// Returns false

// Check nil
result := arr.IsList(nil)
// Returns false

// Check empty slice
result := arr.IsList([]int{})
// Returns true (empty slice is still a list)
Forget

Removes the given key/value pairs from a map. It returns a new map with the specified keys removed, without modifying the original map.

// Remove a single key
original := map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
}
result := arr.Forget(original, "age")
// Returns {"name": "John", "city": "New York"}

// Remove multiple keys
original := map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
    "country": "USA",
}
result := arr.Forget(original, "age", "country")
// Returns {"name": "John", "city": "New York"}

// Remove keys that don't exist
original := map[string]any{"a": 1, "b": 2}
result := arr.Forget(original, "c")
// Returns {"a": 1, "b": 2} (unchanged since key doesn't exist)

// Note: Forget is similar to Except, but with a different parameter order
Only

Returns a new map containing only the specified keys from the original map. It creates a filtered copy of the input map with just the requested keys.

// Keep only specific keys
original := map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
    "country": "USA",
}
result := arr.Only(original, "name", "city")
// Returns {"name": "John", "city": "New York"}

// Request keys that don't exist
original := map[string]any{"a": 1, "b": 2}
result := arr.Only(original, "a", "c")
// Returns {"a": 1} (only existing keys are included)

// Request no keys
original := map[string]any{"a": 1, "b": 2}
result := arr.Only(original)
// Returns {} (empty map)

// Note: Only is the opposite of Except - it keeps only the specified keys
Set

Sets a value at a specified key path in a map, supporting nested paths with dot notation.

// Set a value at a specific key
data := map[string]any{"user": map[string]any{"name": "John"}}
result := arr.Set(data, "user.age", 30)
// result: {"user": {"name": "John", "age": 30}}

// Set a value at a non-existent path (creates intermediate maps)
data := map[string]any{}
result := arr.Set(data, "user.profile.verified", true)
// result: {"user": {"profile": {"verified": true}}}

// Set a value at the root level
data := map[string]any{"status": "pending"}
result := arr.Set(data, "status", "active")
// result: {"status": "active"}

// Empty key returns the original map
data := map[string]any{"a": 1}
result := arr.Set(data, "", "value")
// result: {"a": 1}
SortByKey

Sorts a map by keys in ascending alphabetical order.

// Sort a map by keys
data := map[string]any{"c": 3, "a": 1, "b": 2}
result := arr.SortByKey(data)
// result: {"a": 1, "b": 2, "c": 3}

// Sort an empty map
result := arr.SortByKey(map[string]any{})
// result: {} (empty map)
SortByKeyDesc

Sorts a map by keys in descending alphabetical order.

// Sort a map by keys in descending order
data := map[string]any{"a": 1, "b": 2, "c": 3}
result := arr.SortByKeyDesc(data)
// result: {"c": 3, "b": 2, "a": 1}

// Sort an empty map
result := arr.SortByKeyDesc(map[string]any{})
// result: {} (empty map)
SortRecursive

Recursively sorts maps by keys and nested arrays/maps.

// Sort a nested map structure
data := map[string]any{
    "c": 3,
    "a": map[string]any{"z": 26, "x": 24},
    "b": []any{2, 1, 3}
}
result := arr.SortRecursive(data)
// result: {
//   "a": {"x": 24, "z": 26},
//   "b": [2, 1, 3], // Note: array order is preserved
//   "c": 3
// }

// Sort a simple map
data := map[string]any{"c": 3, "a": 1, "b": 2}
result := arr.SortRecursive(data)
// result: {"a": 1, "b": 2, "c": 3}

// Sort a non-map value
result := arr.SortRecursive(42)
// result: 42 (non-map values are returned as is)
MapFilterMap

Creates a new map by filtering entries from the original map based on a predicate function.

Parameters:

  • m: The source map
  • predicate: A function that takes a key and value and returns a boolean

Returns:

  • A new map containing only the entries for which the predicate returns true
// Filter a map to keep only entries with even values
data := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}
evens := arr.MapFilterMap(data, func(k string, v int) bool {
    return v%2 == 0
})
// evens: {"b": 2, "d": 4}

// Keep only entries where key is "a" or "c"
filtered := arr.MapFilterMap(data, func(k string, v int) bool {
    return k == "a" || k == "c"
})
// filtered: {"a": 1, "c": 3}
MapInvertMap

Creates a new map by swapping the keys and values of the original map.

Parameters:

  • m: The source map to invert

Returns:

  • A new map with the keys and values swapped

Notes:

  • If multiple keys map to the same value in the original map, only one key-value pair will be in the result
  • The last key-value pair processed will be the one that appears in the result
data := map[string]int{"a": 1, "b": 2, "c": 3}
inverted := arr.MapInvertMap(data)
// inverted: {1: "a", 2: "b", 3: "c"}

// With duplicate values
data2 := map[string]int{"a": 1, "b": 2, "c": 1}
inverted2 := arr.MapInvertMap(data2)
// inverted2 might be {1: "c", 2: "b"} or {1: "a", 2: "b"} depending on map iteration order
MapGetOrDefault

Safely retrieves a value from a map, returning a default value if the key doesn't exist.

Parameters:

  • m: The source map
  • key: The key to look up
  • defaultValue: The value to return if the key doesn't exist

Returns:

  • The value associated with the key, or the default value if the key doesn't exist
data := map[string]int{"a": 1, "b": 2, "c": 3}

value := arr.MapGetOrDefault(data, "b", 0)
// value: 2

value = arr.MapGetOrDefault(data, "d", 0)
// value: 0 (default value)
MapGetOrInsert

Retrieves a value from a map, or inserts a default value if the key doesn't exist.

Parameters:

  • m: The source map (will be modified if the key doesn't exist)
  • key: The key to look up
  • defaultValue: The value to insert and return if the key doesn't exist

Returns:

  • The value associated with the key, or the default value if the key didn't exist
data := map[string]int{"a": 1, "b": 2}

// Key exists
value := arr.MapGetOrInsert(data, "b", 0)
// value: 2, data unchanged: {"a": 1, "b": 2}

// Key doesn't exist
value = arr.MapGetOrInsert(data, "c", 3)
// value: 3, data modified: {"a": 1, "b": 2, "c": 3}
Set Operations
SetContains

Checks if a set (implemented as map[T]struct{}) contains a specific element.

// Create a set
set := map[string]struct{}{
    "apple":  {},
    "banana": {},
    "cherry": {},
}

result := arr.SetContains(set, "banana")
// result: true

result = arr.SetContains(set, "orange")
// result: false
SetToSlice

Converts a set (implemented as map[T]struct{}) to a slice.

// Create a set
set := map[string]struct{}{
    "apple":  {},
    "banana": {},
    "cherry": {},
}

slice := arr.SetToSlice(set)
// slice: []string{"apple", "banana", "cherry"} (order may vary)
SliceToSet

Converts a slice to a set (implemented as map[T]struct{}). This is the inverse operation of SetToSlice.

// Create a slice with duplicate elements
slice := []string{"apple", "banana", "apple", "cherry", "banana"}

set := arr.SliceToSet(slice)
// set: map[string]struct{}{"apple": {}, "banana": {}, "cherry": {}}
// Note: duplicates are automatically removed
SetUnion

Creates a new set containing all elements from both input sets.

set1 := map[string]struct{}{"a": {}, "b": {}, "c": {}}
set2 := map[string]struct{}{"b": {}, "c": {}, "d": {}}

union := arr.SetUnion(set1, set2)
// union: {"a": {}, "b": {}, "c": {}, "d": {}}
SetIntersection

Creates a new set containing only elements that exist in both input sets.

Parameters:

  • set1: The first set
  • set2: The second set

Returns:

  • A new set containing only elements that appear in both set1 and set2
set1 := map[string]struct{}{"a": {}, "b": {}, "c": {}}
set2 := map[string]struct{}{"b": {}, "c": {}, "d": {}}

intersection := arr.SetIntersection(set1, set2)
// intersection: {"b": {}, "c": {}}

Note:

  • The function optimizes performance by iterating over the smaller set
SetDifference

Creates a new set containing elements that are in the first set but not in the second set.

Parameters:

  • set1: The first set (source set)
  • set2: The second set (elements to exclude)

Returns:

  • A new set containing elements that are in set1 but not in set2
set1 := map[string]struct{}{"a": {}, "b": {}, "c": {}}
set2 := map[string]struct{}{"b": {}, "c": {}, "d": {}}

difference := arr.SetDifference(set1, set2)
// difference: {"a": {}}

// Note that the difference is not symmetric:
difference2 := arr.SetDifference(set2, set1)
// difference2: {"d": {}}
Pluck

Extracts a specific property from each element in an array and returns an array of those properties.

// Extract a property from a slice of structs
type Person struct {
    Name string
    Age  int
}
people := []Person{
    {Name: "Alice", Age: 25},
    {Name: "Bob", Age: 30},
    {Name: "Charlie", Age: 35},
}
ages := arr.Pluck(people, func(p Person) int {
    return p.Age
})
// Returns []int{25, 30, 35}

// Works with maps too
people := []map[string]any{
    {"name": "Alice", "age": 25},
    {"name": "Bob", "age": 30},
    {"name": "Charlie", "age": 35},
}
names := arr.Pluck(people, func(p map[string]any) string {
    return p["name"].(string)
})
// Returns []string{"Alice", "Bob", "Charlie"}
Prepend

Adds one or more items to the beginning of a slice. It returns a new slice with the values added at the beginning, without modifying the original slice.

// Prepend a single value
result := arr.Prepend([]int{2, 3, 4}, 1)
// Returns [1, 2, 3, 4]

// Prepend multiple values
result := arr.Prepend([]int{3, 4, 5}, 1, 2)
// Returns [1, 2, 3, 4, 5]

// Prepend to an empty slice
result := arr.Prepend([]string{}, "hello")
// Returns ["hello"]

// Works with any type
result := arr.Prepend([]string{"world"}, "hello")
// Returns ["hello", "world"]

// Prepend no values (returns a copy of the original)
result := arr.Prepend([]int{1, 2, 3})
// Returns [1, 2, 3]
Query

Builds a URL query string from a map. It converts a map into a URL-encoded query string suitable for HTTP requests.

// Simple key-value pairs
result := arr.Query(map[string]any{
    "name": "John Doe",
    "age": 30,
})
// Returns "age=30&name=John+Doe" (order may vary)

// With array values
result := arr.Query(map[string]any{
    "colors": []string{"red", "blue", "green"},
    "id": 123,
})
// Returns "colors%5B%5D=red&colors%5B%5D=blue&colors%5B%5D=green&id=123" (order may vary)
// Decoded: "colors[]=red&colors[]=blue&colors[]=green&id=123"

// With special characters
result := arr.Query(map[string]any{
    "search": "hello world",
    "filter": "price>100",
})
// Returns "filter=price%3E100&search=hello+world" (order may vary)
// Decoded: "filter=price>100&search=hello world"

// Empty map
result := arr.Query(map[string]any{})
// Returns "" (empty string)
RandomOrDefault

Returns a random value from a slice or a default value if the slice is empty. It safely handles empty slices by returning the provided default value.

// Get a random element from a non-empty slice
// Note: The actual returned value will vary due to randomness
result := arr.RandomOrDefault([]int{1, 2, 3, 4, 5}, 0)
// Returns one of 1, 2, 3, 4, or 5

// Get the default value from an empty slice
result := arr.RandomOrDefault([]int{}, 0)
// Returns 0

License

This package is licensed under the MIT License - see the LICENSE file for details.

Documentation

Overview

Package arr provides utility functions for array/slice manipulation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Accessible added in v1.1.0

func Accessible(value any) bool

Accessible checks if the given value can be accessed as an array, slice, or map. It returns true if the value is an array, slice, or map, and false otherwise.

Parameters:

  • value: The value to check

Returns:

  • true if the value is an array, slice, or map, false otherwise

Example:

// Check arrays and slices
Accessible([]int{1, 2, 3}) // Returns true
Accessible([3]string{"a", "b", "c"}) // Returns true

// Check maps
Accessible(map[string]int{"a": 1, "b": 2}) // Returns true

// Check other types
Accessible(42) // Returns false
Accessible("hello") // Returns false
Accessible(struct{}{}) // Returns false

// Check nil
Accessible(nil) // Returns false

// Check pointers to arrays/slices/maps
arr := []int{1, 2, 3}
Accessible(&arr) // Returns false (it's a pointer, not directly accessible)

func Add added in v1.1.0

func Add(array map[string]any, key string, value any) map[string]any

Add adds a key/value pair to a map if the key doesn't already exist. It returns a new map without modifying the original.

Parameters:

  • array: The input map to add the key/value pair to
  • key: The key to add
  • value: The value to associate with the key

Returns:

  • A new map with the key/value pair added (if the key didn't exist)

Example:

// Add a new key/value pair
original := map[string]any{"name": "John", "age": 30}
result := Add(original, "city", "New York")
// result = {"name": "John", "age": 30, "city": "New York"}
// original remains unchanged

// Try to add an existing key
original := map[string]any{"name": "John", "age": 30}
result := Add(original, "name", "Jane")
// result = {"name": "John", "age": 30}
// The key "name" already exists, so the value is not changed

// Add to an empty map
empty := map[string]any{}
result := Add(empty, "status", "active")
// result = {"status": "active"}

func Chunk

func Chunk[T any](array []T, size int) [][]T

Chunk splits an array into groups of the specified size.

Parameters:

  • array: The array to split into chunks
  • size: The size of each chunk

Returns:

  • [][]T: A new array containing chunks of the original array

Example:

Chunk([]int{1, 2, 3, 4}, 2) -> [][]int{{1, 2}, {3, 4}}
Chunk([]string{"a", "b", "c", "d", "e"}, 2) -> [][]string{{"a", "b"}, {"c", "d"}, {"e"}}

func Collapse added in v1.1.0

func Collapse(arrays [][]any) []any

Collapse collapses a slice of slices into a single slice. It flattens a two-dimensional slice into a one-dimensional slice.

Parameters:

  • arrays: A slice of slices to collapse

Returns:

  • A single slice containing all elements from the input slices

Example:

// Collapse multiple slices into one
Collapse([][]any{
    {1, 2, 3},
    {4, 5},
    {6, 7, 8, 9},
}) // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9]

// Collapse with mixed types
Collapse([][]any{
    {"a", "b"},
    {1, 2},
    {true, false},
}) // Returns ["a", "b", 1, 2, true, false]

// Collapse with empty slices
Collapse([][]any{
    {1, 2},
    {},
    {3, 4},
}) // Returns [1, 2, 3, 4]

// Collapse an empty slice
Collapse([][]any{}) // Returns []

func Compact

func Compact[T comparable](array []T) []T

Compact removes falsey values from an array. In Go, we consider nil, zero values, and empty collections as falsey.

Parameters:

  • array: The array to compact

Returns:

  • []T: A new array with all falsey values removed

Example:

Compact([]int{0, 1, 2, 0, 3}) -> []int{1, 2, 3}
Compact([]string{"", "a", "", "b"}) -> []string{"a", "b"}

func Concat

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

Concat concatenates arrays together.

Parameters:

  • arrays: Variable number of arrays to concatenate

Returns:

  • []T: A new array containing all elements from the input arrays

Example:

Concat([]int{1, 2}, []int{3, 4}) -> []int{1, 2, 3, 4}
Concat([]string{"a", "b"}, []string{"c"}, []string{"d", "e"}) -> []string{"a", "b", "c", "d", "e"}

func Contains added in v1.1.0

func Contains[T comparable](slice []T, element T) bool

Contains checks if a slice contains a specific element. It returns true if the element is found, false otherwise.

Parameters:

  • slice: The input slice to search in
  • element: The element to search for

Returns:

  • true if the element is found in the slice, false otherwise

Example:

// Check if a number exists in a slice
Contains([]int{1, 2, 3, 4}, 3) // Returns true
Contains([]int{1, 2, 3, 4}, 5) // Returns false

// Check if a string exists in a slice
Contains([]string{"apple", "banana", "orange"}, "banana") // Returns true
Contains([]string{"apple", "banana", "orange"}, "grape") // Returns false

func CrossJoin added in v1.1.0

func CrossJoin[T any](arrays ...[]T) [][]T

CrossJoin cross joins the given arrays, returning a cartesian product with all possible permutations. It generates all possible combinations by taking one element from each input array.

Parameters:

  • arrays: Variable number of slices to cross join

Returns:

  • A slice of slices where each inner slice contains one element from each input array

Example:

// Cross join two arrays
CrossJoin([]int{1, 2}, []int{3, 4})
// Returns [[1, 3], [1, 4], [2, 3], [2, 4]]

// Cross join three arrays
CrossJoin([]string{"a", "b"}, []string{"c", "d"}, []string{"e", "f"})
// Returns [
//   ["a", "c", "e"], ["a", "c", "f"],
//   ["a", "d", "e"], ["a", "d", "f"],
//   ["b", "c", "e"], ["b", "c", "f"],
//   ["b", "d", "e"], ["b", "d", "f"]
// ]

// Cross join with a single array
CrossJoin([]int{1, 2, 3})
// Returns [[1], [2], [3]]

// Cross join with an empty array
CrossJoin([]int{}, []int{1, 2})
// Returns [] (empty result because one array is empty)

// Cross join with no arrays
CrossJoin[int]()
// Returns [] (empty result)

func Difference

func Difference[T comparable](array []T, others ...[]T) []T

Difference returns an array of elements that are in the first array but not in the others.

Parameters:

  • array: The base array to compare against
  • others: Variable number of arrays to compare with the base array

Returns:

  • []T: A new array containing elements that are in the base array but not in any of the other arrays

Example:

Difference([]int{1, 2, 3}, []int{2, 3, 4}) -> []int{1}
Difference([]string{"a", "b", "c"}, []string{"b"}, []string{"c", "d"}) -> []string{"a"}

func Divide added in v1.1.0

func Divide(array map[string]any) ([]string, []any)

Divide returns two slices, one containing the keys, and the other containing the values of the original map. It separates a map into its keys and values while preserving the corresponding order.

Parameters:

  • array: The input map to divide

Returns:

  • A slice containing all the keys from the map
  • A slice containing all the values from the map

Example:

// Divide a map into keys and values
keys, values := Divide(map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
})
// keys could be ["name", "age", "city"] (order may vary)
// values could be ["John", 30, "New York"] (in the same order as keys)

// Divide an empty map
keys, values := Divide(map[string]any{})
// keys = [] (empty slice)
// values = [] (empty slice)

// Note: The order of keys and values is not guaranteed to be the same across different runs
// due to the non-deterministic iteration order of Go maps

func Dot added in v1.1.0

func Dot(array map[string]any) map[string]any

Dot flattens a multi-dimensional map into a single level map with "dot" notation. It converts nested maps into a flat map where keys are paths to values using dot separators.

Parameters:

  • array: The input nested map to flatten

Returns:

  • A flattened map with dot notation keys

Example:

// Flatten a nested map
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
            "zip": 10001,
        },
    },
    "status": "active",
}

flat := Dot(nested)
// Returns:
// {
//    "user.name": "John",
//    "user.address.city": "New York",
//    "user.address.zip": 10001,
//    "status": "active"
// }

// Flatten an empty map
Dot(map[string]any{}) // Returns an empty map

// Flatten a map with no nested structures
Dot(map[string]any{"a": 1, "b": 2}) // Returns the same map {"a": 1, "b": 2}

func Drop

func Drop[T any](array []T, n int) []T

Drop creates a slice with n elements dropped from the beginning.

Parameters:

  • array: The input array
  • n: Number of elements to drop from the beginning

Returns:

  • []T: A new array with the first n elements removed

Example:

Drop([]int{1, 2, 3, 4}, 2) -> []int{3, 4}
Drop([]string{"a", "b", "c"}, 1) -> []string{"b", "c"}

func DropRight

func DropRight[T any](array []T, n int) []T

DropRight creates a slice with n elements dropped from the end.

Parameters:

  • array: The input array
  • n: Number of elements to drop from the end

Returns:

  • []T: A new array with the last n elements removed

Example:

DropRight([]int{1, 2, 3, 4}, 2) -> []int{1, 2}
DropRight([]string{"a", "b", "c"}, 1) -> []string{"a", "b"}

func Except added in v1.1.0

func Except(array map[string]any, keys ...string) map[string]any

Except returns a new map with the specified keys removed from the original map. It creates a copy of the input map excluding the specified keys.

Parameters:

  • array: The input map to filter
  • keys: Variable number of keys to exclude from the result

Returns:

  • A new map with the specified keys removed

Example:

// Remove specific keys from a map
original := map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
    "country": "USA",
}
result := Except(original, "age", "country")
// Returns {"name": "John", "city": "New York"}

// Remove keys that don't exist
original := map[string]any{"a": 1, "b": 2}
result := Except(original, "c", "d")
// Returns {"a": 1, "b": 2} (unchanged since keys don't exist)

// Remove all keys
original := map[string]any{"a": 1, "b": 2}
result := Except(original, "a", "b")
// Returns {} (empty map)

// No keys to remove
original := map[string]any{"a": 1, "b": 2}
result := Except(original)
// Returns {"a": 1, "b": 2} (unchanged)

func Exists added in v1.1.0

func Exists(array map[string]any, key string) bool

Exists checks if the given key exists in the map. It returns true if the key exists, false otherwise.

Parameters:

  • array: The map to check
  • key: The key to look for

Returns:

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

Example:

// Check if a key exists
user := map[string]any{
    "name": "John",
    "age": 30,
}
Exists(user, "name") // Returns true
Exists(user, "email") // Returns false

// Check in an empty map
Exists(map[string]any{}, "key") // Returns false

// Check with a nil map
var nilMap map[string]any
Exists(nilMap, "key") // Returns false (safe to use with nil maps)

func Fill

func Fill[T any](array []T, value T, start, end int) []T

Fill fills elements of array with value from start up to, but not including, end.

Parameters:

  • array: The input array
  • value: The value to fill the array with
  • start: The starting index (inclusive)
  • end: The ending index (exclusive)

Returns:

  • []T: A new array with elements filled with the specified value

Example:

Fill([]int{1, 2, 3, 4}, 0, 1, 3) -> []int{1, 0, 0, 4}
Fill([]string{"a", "b", "c", "d"}, "x", 0, 2) -> []string{"x", "x", "c", "d"}

func Filter added in v1.1.0

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

Filter returns a new slice containing only the elements that satisfy the predicate function. It does not modify the original slice.

Parameters:

  • slice: The input slice to filter
  • predicate: A function that returns true for elements to keep and false for elements to exclude

Returns:

  • A new slice containing only the elements for which the predicate returns true

Example:

// Filter even numbers
Filter([]int{1, 2, 3, 4, 5}, func(n int) bool { return n%2 == 0 }) // Returns [2, 4]

// Filter strings longer than 5 characters
Filter([]string{"apple", "banana", "kiwi", "strawberry"}, func(s string) bool {
    return len(s) > 5
}) // Returns ["banana", "strawberry"]

// Filter structs based on a condition
type Person struct {
    Name string
    Age int
}
people := []Person{
    {Name: "Alice", Age: 25},
    {Name: "Bob", Age: 17},
    {Name: "Charlie", Age: 30},
}
adults := Filter(people, func(p Person) bool { return p.Age >= 18 })
// Returns [{Name: "Alice", Age: 25}, {Name: "Charlie", Age: 30}]

func Find added in v1.1.0

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

Find returns the first element in the slice that satisfies the predicate function and a boolean indicating whether such an element was found.

Parameters:

  • slice: The input slice to search in
  • predicate: A function that returns true for the element to find

Returns:

  • The first element for which the predicate returns true
  • A boolean indicating whether such an element was found (true if found, false otherwise)

Example:

// Find the first even number
even, found := Find([]int{1, 3, 4, 5, 6}, func(n int) bool { return n%2 == 0 })
// even = 4, found = true

// Find a string with a specific prefix
str, found := Find([]string{"apple", "banana", "cherry"}, func(s string) bool {
    return strings.HasPrefix(s, "b")
})
// str = "banana", found = true

// Find a struct that matches a condition
type Product struct {
    Name string
    Price float64
}
products := []Product{
    {Name: "Laptop", Price: 1200},
    {Name: "Phone", Price: 800},
    {Name: "Tablet", Price: 500},
}
affordable, found := Find(products, func(p Product) bool { return p.Price < 1000 })
// affordable = {Name: "Phone", Price: 800}, found = true

// When no element is found
num, found := Find([]int{1, 3, 5}, func(n int) bool { return n%2 == 0 })
// num = 0 (zero value), found = false

func FindIndex

func FindIndex[T any](array []T, predicate func(T) bool) int

FindIndex returns the index of the first element that satisfies the predicate function.

Parameters:

  • array: The input array
  • predicate: A function that returns true for elements that satisfy the condition

Returns:

  • int: The index of the first element that satisfies the predicate, or -1 if none found

Example:

FindIndex([]int{1, 2, 3, 4}, func(n int) bool { return n > 2 }) -> 2
FindIndex([]string{"a", "b", "c"}, func(s string) bool { return s == "b" }) -> 1

func FindLastIndex

func FindLastIndex[T any](array []T, predicate func(T) bool) int

FindLastIndex returns the index of the last element that satisfies the predicate function.

Parameters:

  • array: The input array
  • predicate: A function that returns true for elements that satisfy the condition

Returns:

  • int: The index of the last element that satisfies the predicate, or -1 if none found

Example:

FindLastIndex([]int{1, 2, 3, 4}, func(n int) bool { return n > 2 }) -> 3
FindLastIndex([]string{"a", "b", "c", "b"}, func(s string) bool { return s == "b" }) -> 3

func First

func First[T any](array []T) (T, bool)

First returns the first element of an array.

Parameters:

  • array: The input array

Returns:

  • T: The first element of the array
  • bool: True if the array is not empty, false otherwise

Example:

First([]int{1, 2, 3}) -> 1, true
First([]string{"a", "b"}) -> "a", true
First([]int{}) -> 0, false

func FirstOrDefault added in v1.1.0

func FirstOrDefault[T any](array []T, defaultValue T) T

FirstOrDefault returns the first element in the array, or a default value if the array is empty. It safely handles empty arrays by returning the provided default value.

Parameters:

  • array: The input array to get the first element from
  • defaultValue: The value to return if the array is empty

Returns:

  • The first element of the array if it exists, otherwise the default value

Example:

// Get the first element from a non-empty array
FirstOrDefault([]int{1, 2, 3}, 0) // Returns 1

// Get the default value from an empty array
FirstOrDefault([]int{}, 0) // Returns 0

// Works with any type
FirstOrDefault([]string{"apple", "banana"}, "default") // Returns "apple"
FirstOrDefault([]string{}, "default") // Returns "default"

// Works with structs
type User struct {
    Name string
}
users := []User{{Name: "Alice"}, {Name: "Bob"}}
defaultUser := User{Name: "Unknown"}
FirstOrDefault(users, defaultUser) // Returns {Name: "Alice"}
FirstOrDefault([]User{}, defaultUser) // Returns {Name: "Unknown"}

func Flatten

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

Flatten flattens an array a single level deep.

Parameters:

  • array: The nested array to flatten

Returns:

  • []T: A new array with all nested elements combined into a single level

Example:

Flatten([][]int{{1, 2}, {3, 4}}) -> []int{1, 2, 3, 4}
Flatten([][]string{{"a", "b"}, {"c"}}) -> []string{"a", "b", "c"}

func Forget added in v1.1.0

func Forget(array map[string]any, keys ...string) map[string]any

Forget removes the given key/value pairs from the map. It returns a new map with the specified keys removed, without modifying the original map.

Parameters:

  • array: The input map to remove keys from
  • keys: Variable number of keys to remove

Returns:

  • A new map with the specified keys removed

Example:

// Remove a single key
original := map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
}
result := Forget(original, "age")
// Returns {"name": "John", "city": "New York"}

// Remove multiple keys
original := map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
    "country": "USA",
}
result := Forget(original, "age", "country")
// Returns {"name": "John", "city": "New York"}

// Remove keys that don't exist
original := map[string]any{"a": 1, "b": 2}
result := Forget(original, "c")
// Returns {"a": 1, "b": 2} (unchanged since key doesn't exist)

// Note: Forget is similar to Except, but with a different parameter order

func Get added in v1.1.0

func Get(array map[string]any, key string, defaultValue any) any

Get retrieves a value from a map using "dot" notation for accessing nested values. It allows accessing deeply nested values in a map using dot-separated keys. If the key doesn't exist, it returns the provided default value.

Parameters:

  • array: The input map to retrieve the value from
  • key: The key to look for, using dot notation for nested keys
  • defaultValue: The value to return if the key doesn't exist

Returns:

  • The value associated with the key if it exists, otherwise the default value

Example:

// Simple key access
data := map[string]any{
    "name": "John",
    "age": 30,
}
Get(data, "name", "Unknown") // Returns "John"
Get(data, "email", "N/A") // Returns "N/A" (key doesn't exist)

// Nested key access
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
            "zip": 10001,
        },
    },
    "status": "active",
}

Get(nested, "user.name", "Unknown") // Returns "John"
Get(nested, "user.address.city", "Unknown") // Returns "New York"
Get(nested, "user.address.country", "USA") // Returns "USA" (key doesn't exist)
Get(nested, "user.email", nil) // Returns nil (key doesn't exist)

// Empty key returns the entire map
Get(nested, "", nil) // Returns the entire nested map

func GroupBy added in v1.1.0

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

GroupBy groups elements in a slice by a key generated from each element. It creates a map where each key is the result of applying the keyFunc to an element, and each value is a slice of elements that produced that key.

Parameters:

  • slice: The input slice to group
  • keyFunc: A function that generates a key for each element

Returns:

  • A map where keys are the generated keys and values are slices of elements

Example:

// Group numbers by their remainder when divided by 3
GroupBy([]int{1, 2, 3, 4, 5, 6}, func(n int) int {
    return n % 3
})
// Returns map[0:[3, 6] 1:[1, 4] 2:[2, 5]]

// Group strings by their first letter
GroupBy([]string{"apple", "banana", "apricot", "blueberry"}, func(s string) string {
    return string(s[0])
})
// Returns map["a":["apple", "apricot"] "b":["banana", "blueberry"]]

// Group structs by a field
type Person struct {
    Name string
    Age int
}
people := []Person{
    {Name: "Alice", Age: 25},
    {Name: "Bob", Age: 30},
    {Name: "Charlie", Age: 25},
    {Name: "Dave", Age: 30},
}
byAge := GroupBy(people, func(p Person) int { return p.Age })
// Returns map[25:[{Name: "Alice", Age: 25}, {Name: "Charlie", Age: 25}]
//            30:[{Name: "Bob", Age: 30}, {Name: "Dave", Age: 30}]]

func Has added in v1.1.0

func Has(array map[string]any, keys ...string) bool

Has determines if all of the specified keys exist in the map using "dot" notation. It checks if every key in the provided list exists in the map, including nested keys. Returns true only if all keys exist.

Parameters:

  • array: The input map to check
  • keys: Variable number of keys to check for existence

Returns:

  • true if all specified keys exist in the map, false otherwise

Example:

// Check simple keys
data := map[string]any{
    "name": "John",
    "age": 30,
}
Has(data, "name") // Returns true
Has(data, "email") // Returns false
Has(data, "name", "age") // Returns true (both keys exist)
Has(data, "name", "email") // Returns false (not all keys exist)

// Check nested keys
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
        },
    },
}

Has(nested, "user.name") // Returns true
Has(nested, "user.address.city") // Returns true
Has(nested, "user.address.country") // Returns false
Has(nested, "user.name", "user.address.city") // Returns true (both keys exist)

// Empty keys list
Has(data) // Returns false (no keys to check)

func HasAny added in v1.1.0

func HasAny(array map[string]any, keys ...string) bool

HasAny determines if any of the specified keys exist in the map using "dot" notation. It checks if at least one key in the provided list exists in the map, including nested keys. Returns true if at least one key exists.

Parameters:

  • array: The input map to check
  • keys: Variable number of keys to check for existence

Returns:

  • true if at least one of the specified keys exists in the map, false otherwise

Example:

// Check simple keys
data := map[string]any{
    "name": "John",
    "age": 30,
}
HasAny(data, "name") // Returns true
HasAny(data, "email") // Returns false
HasAny(data, "name", "email") // Returns true (at least one key exists)
HasAny(data, "email", "phone") // Returns false (none of the keys exist)

// Check nested keys
nested := map[string]any{
    "user": map[string]any{
        "name": "John",
        "address": map[string]any{
            "city": "New York",
        },
    },
}

HasAny(nested, "user.name") // Returns true
HasAny(nested, "user.address.city") // Returns true
HasAny(nested, "user.address.country") // Returns false
HasAny(nested, "user.address.country", "user.name") // Returns true (at least one key exists)

// Empty keys list
HasAny(data) // Returns false (no keys to check)

func Includes

func Includes[T comparable](array []T, value T) bool

Includes checks if a value is in the array.

Parameters:

  • array: The array to search in
  • value: The value to search for

Returns:

  • bool: True if the value is found in the array, false otherwise

Example:

Includes([]int{1, 2, 3}, 2) -> true
Includes([]string{"a", "b", "c"}, "d") -> false

func IndexOf

func IndexOf[T comparable](array []T, value T) int

IndexOf returns the index of the first occurrence of value in array.

Parameters:

  • array: The array to search in
  • value: The value to search for

Returns:

  • int: The index of the first occurrence of the value, or -1 if not found

Example:

IndexOf([]int{1, 2, 3, 2}, 2) -> 1
IndexOf([]string{"a", "b", "c"}, "c") -> 2
IndexOf([]int{1, 2, 3}, 4) -> -1

func Initial

func Initial[T any](array []T) []T

Initial returns all but the last element of an array.

Parameters:

  • array: The input array

Returns:

  • []T: A new array containing all elements except the last one

Example:

Initial([]int{1, 2, 3}) -> []int{1, 2}
Initial([]string{"a", "b", "c"}) -> []string{"a", "b"}
Initial([]int{1}) -> []int{}

func Intersection

func Intersection[T comparable](arrays ...[]T) []T

Intersection returns an array of unique values that are included in all given arrays.

Parameters:

  • arrays: Variable number of arrays to find common elements from

Returns:

  • []T: A new array containing elements that exist in all input arrays

Example:

Intersection([]int{1, 2, 3}, []int{2, 3, 4}) -> []int{2, 3}
Intersection([]string{"a", "b", "c"}, []string{"b", "c", "d"}, []string{"b", "e"}) -> []string{"b"}
Intersection([]int{1, 2}, []int{3, 4}) -> []int{}

func IsAssoc added in v1.1.0

func IsAssoc(array any) bool

IsAssoc determines if a value is an associative array/map (has string keys). It checks if the value is a map with string keys.

Parameters:

  • array: The value to check

Returns:

  • true if the value is a map with string keys, false otherwise

Example:

// Check associative arrays (maps with string keys)
IsAssoc(map[string]any{"name": "John", "age": 30}) // Returns true
IsAssoc(map[string]int{"a": 1, "b": 2}) // Returns true

// Check non-associative arrays
IsAssoc([]int{1, 2, 3}) // Returns false (slice, not a map)
IsAssoc(map[int]string{1: "a", 2: "b"}) // Returns false (map with non-string keys)

// Check other types
IsAssoc(42) // Returns false
IsAssoc("hello") // Returns false

// Check nil
IsAssoc(nil) // Returns false

func IsList added in v1.1.0

func IsList(array any) bool

IsList determines if a value is a list (slice or array). It checks if the value is a slice or array type.

Parameters:

  • array: The value to check

Returns:

  • true if the value is a slice or array, false otherwise

Example:

// Check slices
IsList([]int{1, 2, 3}) // Returns true
IsList([]string{"a", "b", "c"}) // Returns true
IsList([]any{1, "a", true}) // Returns true

// Check arrays
IsList([3]int{1, 2, 3}) // Returns true
IsList([2]string{"a", "b"}) // Returns true

// Check non-list types
IsList(map[string]int{"a": 1, "b": 2}) // Returns false (map, not a slice/array)
IsList(42) // Returns false
IsList("hello") // Returns false

// Check nil
IsList(nil) // Returns false

// Check empty slice
IsList([]int{}) // Returns true (empty slice is still a list)

func Join

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

Join joins all elements of an array into a string.

Parameters:

  • array: The array of elements to join
  • separator: The string to insert between elements

Returns:

  • string: A string containing all array elements joined with the separator

Example:

Join([]int{1, 2, 3}, ",") -> "1,2,3"
Join([]string{"a", "b", "c"}, "-") -> "a-b-c"
Join([]bool{true, false}, " and ") -> "true and false"

func KeyBy added in v1.1.0

func KeyBy[T any, K comparable](array []T, keyFunc func(T) K) map[K]T

KeyBy creates a map from an array, using the result of the key function as the map key. It transforms a slice into a map where each element is indexed by a key derived from the element itself.

Parameters:

  • array: The input slice to transform into a map
  • keyFunc: A function that generates a key for each element

Returns:

  • A map where keys are generated by the keyFunc and values are elements from the input array

Example:

// Key numbers by themselves
KeyBy([]int{1, 2, 3}, func(n int) int { return n })
// Returns map[1:1 2:2 3:3]

// Key strings by their length
KeyBy([]string{"apple", "banana", "kiwi"}, func(s string) int {
    return len(s)
})
// Returns map[5:"apple" 6:"banana" 4:"kiwi"]

// Key structs by a field
type User struct {
    ID int
    Name string
}
users := []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
    {ID: 3, Name: "Charlie"},
}
userMap := KeyBy(users, func(u User) int { return u.ID })
// Returns map[1:{ID:1 Name:"Alice"} 2:{ID:2 Name:"Bob"} 3:{ID:3 Name:"Charlie"}]

// Note: If multiple elements produce the same key, later elements will overwrite earlier ones

func Last

func Last[T any](array []T) (T, bool)

Last returns the last element of an array.

Parameters:

  • array: The input array

Returns:

  • T: The last element of the array
  • bool: True if the array is not empty, false otherwise

Example:

Last([]int{1, 2, 3}) -> 3, true
Last([]string{"a", "b"}) -> "b", true
Last([]int{}) -> 0, false

func LastIndexOf

func LastIndexOf[T comparable](array []T, value T) int

LastIndexOf returns the index of the last occurrence of value in array.

Parameters:

  • array: The array to search in
  • value: The value to search for

Returns:

  • int: The index of the last occurrence of the value, or -1 if not found

Example:

LastIndexOf([]int{1, 2, 3, 2}, 2) -> 3
LastIndexOf([]string{"a", "b", "c", "b"}, "b") -> 3
LastIndexOf([]int{1, 2, 3}, 4) -> -1

func LastOrDefault added in v1.1.0

func LastOrDefault[T any](array []T, defaultValue T) T

LastOrDefault returns the last element in the array, or a default value if the array is empty. It safely handles empty arrays by returning the provided default value.

Parameters:

  • array: The input array to get the last element from
  • defaultValue: The value to return if the array is empty

Returns:

  • The last element of the array if it exists, otherwise the default value

Example:

// Get the last element from a non-empty array
LastOrDefault([]int{1, 2, 3}, 0) // Returns 3

// Get the default value from an empty array
LastOrDefault([]int{}, 0) // Returns 0

// Works with any type
LastOrDefault([]string{"apple", "banana"}, "default") // Returns "banana"
LastOrDefault([]string{}, "default") // Returns "default"

// Works with structs
type User struct {
    Name string
}
users := []User{{Name: "Alice"}, {Name: "Bob"}}
defaultUser := User{Name: "Unknown"}
LastOrDefault(users, defaultUser) // Returns {Name: "Bob"}
LastOrDefault([]User{}, defaultUser) // Returns {Name: "Unknown"}

func Map added in v1.1.0

func Map[T any, R any](slice []T, mapFunc func(T) R) []R

Map applies a function to each element in a slice and returns a new slice with the results. It transforms each element from type T to type R using the provided mapping function.

Parameters:

  • slice: The input slice to transform
  • mapFunc: A function that transforms each element from type T to type R

Returns:

  • A new slice containing the transformed elements

Example:

// Double each number
Map([]int{1, 2, 3}, func(n int) int { return n * 2 }) // Returns [2, 4, 6]

// Convert numbers to strings
Map([]int{1, 2, 3}, func(n int) string { return fmt.Sprintf("Number: %d", n) })
// Returns ["Number: 1", "Number: 2", "Number: 3"]

// Extract a field from structs
type User struct {
    ID int
    Name string
}
users := []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
    {ID: 3, Name: "Charlie"},
}
names := Map(users, func(u User) string { return u.Name })
// Returns ["Alice", "Bob", "Charlie"]

func MapDiffMaps added in v1.1.0

func MapDiffMaps[K comparable, V comparable](m1, m2 map[K]V) (added, removed, changed map[K]V)

MapDiffMaps identifies the differences between two maps.

Parameters:

  • m1: The first map (considered the "original" map)
  • m2: The second map (considered the "new" map)

Returns:

  • added: A map containing keys in m2 that are not in m1 (with their values from m2)
  • removed: A map containing keys in m1 that are not in m2 (with their values from m1)
  • changed: A map containing keys that exist in both maps but have different values (with their values from m2)

Example:

original := map[string]int{"a": 1, "b": 2, "c": 3}
new := map[string]int{"b": 20, "c": 3, "d": 4}

added, removed, changed := arr.MapDiffMaps(original, new)
// added: {"d": 4}        - key "d" is in new but not in original
// removed: {"a": 1}      - key "a" is in original but not in new
// changed: {"b": 20}     - key "b" is in both but values differ (2 vs 20)
// Note: key "c" is not in any result map because it's unchanged

func MapEqualMaps added in v1.1.0

func MapEqualMaps[K, V comparable](m1, m2 map[K]V) bool

MapEqualMaps checks if two maps contain exactly the same key-value pairs.

Parameters:

  • m1: The first map to compare
  • m2: The second map to compare

Returns:

  • true if both maps have the same keys with the same values, false otherwise

Example:

map1 := map[string]int{"a": 1, "b": 2, "c": 3}
map2 := map[string]int{"c": 3, "b": 2, "a": 1} // Same content, different order
map3 := map[string]int{"a": 1, "b": 2}         // Missing a key
map4 := map[string]int{"a": 1, "b": 2, "c": 4} // Different value

arr.MapEqualMaps(map1, map2) // Returns: true
arr.MapEqualMaps(map1, map3) // Returns: false
arr.MapEqualMaps(map1, map4) // Returns: false

func MapFilterMap added in v1.1.0

func MapFilterMap[K comparable, V any](m map[K]V, predicate func(K, V) bool) map[K]V

MapFilterMap creates a new map containing only the key-value pairs that satisfy a predicate function.

Parameters:

  • m: The source map to filter
  • predicate: A function that takes a key and value and returns true if the pair should be included

Returns:

  • A new map containing only the key-value pairs that satisfy the predicate

Example:

data := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}

// Keep only entries with even values
evens := arr.MapFilterMap(data, func(k string, v int) bool {
    return v%2 == 0
})
// evens: {"b": 2, "d": 4}

// Keep only entries where key is "a" or "c"
filtered := arr.MapFilterMap(data, func(k string, v int) bool {
    return k == "a" || k == "c"
})
// filtered: {"a": 1, "c": 3}

func MapFindKey added in v1.1.0

func MapFindKey[K comparable, V comparable](m map[K]V, value V) (K, bool)

MapFindKey finds the first key in a map that corresponds to a specific value.

Parameters:

  • m: The source map to search in
  • value: The value to search for

Returns:

  • The first key that maps to the specified value
  • A boolean indicating whether such a key was found

Example:

data := map[string]int{"a": 1, "b": 2, "c": 1}
key, found := arr.MapFindKey(data, 1)
// key: "a" (or "c" depending on map iteration order), found: true

key, found = arr.MapFindKey(data, 5)
// key: "" (zero value for string), found: false

func MapGetOrDefault added in v1.1.0

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

MapGetOrDefault safely retrieves a value from a map, returning a default value if the key doesn't exist.

Parameters:

  • m: The source map
  • key: The key to look up
  • defaultValue: The value to return if the key doesn't exist

Returns:

  • The value associated with the key, or the default value if the key doesn't exist

Example:

data := map[string]int{"a": 1, "b": 2, "c": 3}

value := arr.MapGetOrDefault(data, "b", 0)
// value: 2

value = arr.MapGetOrDefault(data, "d", 0)
// value: 0 (default value)

func MapGetOrInsert added in v1.1.0

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

MapGetOrInsert retrieves a value from a map, or inserts a default value if the key doesn't exist.

Parameters:

  • m: The source map (will be modified if the key doesn't exist)
  • key: The key to look up
  • defaultValue: The value to insert and return if the key doesn't exist

Returns:

  • The value associated with the key, or the default value if the key didn't exist

Example:

data := map[string]int{"a": 1, "b": 2}

// Key exists
value := arr.MapGetOrInsert(data, "b", 0)
// value: 2, data unchanged: {"a": 1, "b": 2}

// Key doesn't exist
value = arr.MapGetOrInsert(data, "c", 3)
// value: 3, data modified: {"a": 1, "b": 2, "c": 3}

func MapInvertMap added in v1.1.0

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

MapInvertMap creates a new map by swapping the keys and values of the original map.

Parameters:

  • m: The source map to invert

Returns:

  • A new map with the keys and values swapped

Notes:

  • If multiple keys map to the same value in the original map, only one key-value pair will be in the result
  • The last key-value pair processed will be the one that appears in the result

Example:

data := map[string]int{"a": 1, "b": 2, "c": 3}
inverted := arr.MapInvertMap(data)
// inverted: {1: "a", 2: "b", 3: "c"}

// With duplicate values
data2 := map[string]int{"a": 1, "b": 2, "c": 1}
inverted2 := arr.MapInvertMap(data2)
// inverted2 might be {1: "c", 2: "b"} or {1: "a", 2: "b"} depending on map iteration order

func MapKeys added in v1.1.0

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

MapKeys extracts all keys from a map into a slice.

Parameters:

  • m: The source map

Returns:

  • A slice containing all keys from the map

Example:

data := map[string]int{"a": 1, "b": 2, "c": 3}
keys := arr.MapKeys(data)
// keys: []string{"a", "b", "c"} (order may vary)

func MapMerge added in v1.1.0

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

MapMerge combines multiple maps into a single new map.

Parameters:

  • maps: Variable number of maps to merge

Returns:

  • A new map containing all key-value pairs from the input maps

Notes:

  • If there are duplicate keys, values from later maps will overwrite earlier ones

Example:

map1 := map[string]int{"a": 1, "b": 2}
map2 := map[string]int{"b": 3, "c": 4}
result := arr.MapMerge(map1, map2)
// result: {"a": 1, "b": 3, "c": 4}

func MapSliceToMap added in v1.1.0

func MapSliceToMap[K comparable, V any](slice []struct {
	Key   K
	Value V
}) map[K]V

MapSliceToMap converts a slice of key-value pair structs to a map. This is the inverse operation of MapToSlice.

Parameters:

  • slice: A slice of structs, each containing a Key and Value field

Returns:

  • A map with keys and values from the input slice

Example:

pairs := []struct {
    Key   string
    Value int
}{
    {Key: "a", Value: 1},
    {Key: "b", Value: 2},
    {Key: "c", Value: 3},
}

data := arr.MapSliceToMap(pairs)
// data: map[string]int{"a": 1, "b": 2, "c": 3}

// If there are duplicate keys, the last one wins:
pairs2 := []struct {
    Key   string
    Value int
}{
    {Key: "a", Value: 1},
    {Key: "a", Value: 10},
}
data2 := arr.MapSliceToMap(pairs2)
// data2: map[string]int{"a": 10}

func MapToSlice added in v1.1.0

func MapToSlice[K comparable, V any](m map[K]V) []struct {
	Key   K
	Value V
}

MapToSlice converts a map to a slice of key-value pair structs.

Parameters:

  • m: The source map to convert

Returns:

  • A slice of structs, each containing a Key and Value field

Example:

data := map[string]int{"a": 1, "b": 2, "c": 3}
pairs := arr.MapToSlice(data)
// pairs is a slice of struct{Key string; Value int} with entries like:
// [{Key: "a", Value: 1}, {Key: "b", Value: 2}, {Key: "c", Value: 3}]
// (order may vary due to map iteration)

// You can iterate over the pairs:
for _, pair := range pairs {
    fmt.Printf("Key: %s, Value: %d\n", pair.Key, pair.Value)
}

func MapValues added in v1.1.0

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

MapValues extracts all values from a map into a slice.

Parameters:

  • m: The source map

Returns:

  • A slice containing all values from the map

Example:

data := map[string]int{"a": 1, "b": 2, "c": 3}
values := arr.MapValues(data)
// values: []int{1, 2, 3} (order may vary)

func MapValuesFn added in v1.1.0

func MapValuesFn[K comparable, V any, R any](m map[K]V, mapFunc func(V) R) map[K]R

MapValuesFn transforms all values in a map using a mapping function.

Parameters:

  • m: The source map
  • mapFunc: A function that transforms values of type V to type R

Returns:

  • A new map with the same keys but transformed values

Example:

data := map[string]int{"a": 1, "b": 2, "c": 3}
doubled := arr.MapValuesFn(data, func(v int) int {
    return v * 2
})
// doubled: {"a": 2, "b": 4, "c": 6}

// Converting types
toString := arr.MapValuesFn(data, func(v int) string {
    return fmt.Sprintf("value-%d", v)
})
// toString: {"a": "value-1", "b": "value-2", "c": "value-3"}

func Nth

func Nth[T any](array []T, n int) (T, bool)

Nth returns the element at index n of array. If n is negative, the nth element from the end is returned.

Parameters:

  • array: The input array
  • n: The index of the element to retrieve (can be negative)

Returns:

  • T: The element at the specified index
  • bool: True if a valid element was found, false otherwise

Example:

Nth([]int{1, 2, 3}, 1) -> 2, true
Nth([]string{"a", "b", "c"}, -1) -> "c", true
Nth([]int{1, 2, 3}, 5) -> 0, false

func Only added in v1.1.0

func Only(array map[string]any, keys ...string) map[string]any

Only returns a new map containing only the specified keys from the original map. It creates a filtered copy of the input map with just the requested keys.

Parameters:

  • array: The input map to filter
  • keys: Variable number of keys to include in the result

Returns:

  • A new map containing only the specified keys and their values

Example:

// Keep only specific keys
original := map[string]any{
    "name": "John",
    "age": 30,
    "city": "New York",
    "country": "USA",
}
result := Only(original, "name", "city")
// Returns {"name": "John", "city": "New York"}

// Request keys that don't exist
original := map[string]any{"a": 1, "b": 2}
result := Only(original, "a", "c")
// Returns {"a": 1} (only existing keys are included)

// Request no keys
original := map[string]any{"a": 1, "b": 2}
result := Only(original)
// Returns {} (empty map)

// Note: Only is the opposite of Except - it keeps only the specified keys
// while Except removes the specified keys

func Pluck added in v1.1.0

func Pluck[T any, V any](array []T, key func(T) V) []V

Pluck extracts a specific property from each element in a slice. It creates a new slice containing the values of a specified property from each element.

Parameters:

  • array: The input slice of elements
  • key: A function that extracts a value from each element

Returns:

  • A slice containing the extracted values

Example:

// Extract a property from structs
type User struct {
    ID int
    Name string
    Age int
}
users := []User{
    {ID: 1, Name: "Alice", Age: 25},
    {ID: 2, Name: "Bob", Age: 30},
    {ID: 3, Name: "Charlie", Age: 35},
}

// Get all names
names := Pluck(users, func(u User) string { return u.Name })
// Returns ["Alice", "Bob", "Charlie"]

// Get all ages
ages := Pluck(users, func(u User) int { return u.Age })
// Returns [25, 30, 35]

// Works with maps too
people := []map[string]any{
    {"name": "Alice", "age": 25},
    {"name": "Bob", "age": 30},
    {"name": "Charlie", "age": 35},
}
names := Pluck(people, func(p map[string]any) string {
    return p["name"].(string)
})
// Returns ["Alice", "Bob", "Charlie"]

func Prepend added in v1.1.0

func Prepend[T any](array []T, values ...T) []T

Prepend adds one or more items to the beginning of a slice. It returns a new slice with the values added at the beginning, without modifying the original slice.

Parameters:

  • array: The original slice
  • values: One or more values to add to the beginning of the slice

Returns:

  • A new slice with the values prepended

Example:

// Prepend a single value
Prepend([]int{2, 3, 4}, 1) // Returns [1, 2, 3, 4]

// Prepend multiple values
Prepend([]int{3, 4, 5}, 1, 2) // Returns [1, 2, 3, 4, 5]

// Prepend to an empty slice
Prepend([]string{}, "hello") // Returns ["hello"]

// Works with any type
Prepend([]string{"world"}, "hello") // Returns ["hello", "world"]

// Prepend no values (returns a copy of the original)
Prepend([]int{1, 2, 3}) // Returns [1, 2, 3]

func Pull

func Pull[T comparable](array []T, values ...T) []T

Pull removes all given values from array.

Parameters:

  • array: The input array
  • values: Variable number of values to remove from the array

Returns:

  • []T: A new array with all specified values removed

Example:

Pull([]int{1, 2, 3, 1, 2, 3}, 2, 3) -> []int{1, 1}
Pull([]string{"a", "b", "c", "a"}, "a") -> []string{"b", "c"}
Pull([]int{1, 2, 3}, 4) -> []int{1, 2, 3}

func Query added in v1.1.0

func Query(array map[string]any) string

Query builds a URL query string from a map. It converts a map into a URL-encoded query string suitable for HTTP requests.

Parameters:

  • array: The input map to convert to a query string

Returns:

  • A URL-encoded query string

Example:

// Simple key-value pairs
Query(map[string]any{
    "name": "John Doe",
    "age": 30,
}) // Returns "age=30&name=John+Doe" (order may vary)

// With array values
Query(map[string]any{
    "colors": []string{"red", "blue", "green"},
    "id": 123,
}) // Returns "colors%5B%5D=red&colors%5B%5D=blue&colors%5B%5D=green&id=123" (order may vary)
// Decoded: "colors[]=red&colors[]=blue&colors[]=green&id=123"

// With special characters
Query(map[string]any{
    "search": "hello world",
    "filter": "price>100",
}) // Returns "filter=price%3E100&search=hello+world" (order may vary)
// Decoded: "filter=price>100&search=hello world"

// Empty map
Query(map[string]any{}) // Returns "" (empty string)

func Random

func Random[T any](slice []T, n int) []T

Random returns n random elements from the given slice without replacement.

Parameters:

  • slice: The input array to select elements from
  • n: The number of random elements to return

Returns:

  • []T: A new array containing n randomly selected elements without replacement

Notes:

  • If n <= 0 or the slice is empty, an empty slice is returned
  • If n >= len(slice), a shuffled copy of the entire slice is returned
  • The original slice is not modified
  • The function uses the Shuffle function internally to randomize the elements

Example:

Random([]int{1, 2, 3, 4, 5}, 3) -> [2, 4, 1]
Random([]string{"a", "b", "c", "d"}, 2) -> ["c", "a"]
Random([]int{1, 2}, 3) -> [2, 1] (returns all elements in random order)

func RandomChoice

func RandomChoice[T any](choices []T) (T, bool)

RandomChoice returns a random element from the given slice.

Parameters:

  • choices: The input array to select a random element from

Returns:

  • T: A randomly selected element from the array
  • bool: True if a valid element was selected, false if the array is empty

Example:

RandomChoice([]string{"a", "b", "c"}) -> "b", true
RandomChoice([]int{1, 2, 3, 4}) -> 3, true
RandomChoice([]int{}) -> 0, false

func RandomOrDefault added in v1.1.0

func RandomOrDefault[T any](array []T, defaultValue T) T

RandomOrDefault returns a random value from a slice or a default value if the slice is empty. It safely handles empty slices by returning the provided default value.

Parameters:

  • array: The input slice to get a random element from
  • defaultValue: The value to return if the slice is empty

Returns:

  • A random element from the slice if it's not empty, otherwise the default value

Example:

// Get a random element from a non-empty slice
// Note: The actual returned value will vary due to randomness
RandomOrDefault([]int{1, 2, 3, 4, 5}, 0) // Returns one of 1, 2, 3, 4, or 5

// Get the default value from an empty slice
RandomOrDefault([]int{}, 0) // Returns 0

// Works with any type
RandomOrDefault([]string{"apple", "banana", "cherry"}, "default")
// Returns one of "apple", "banana", or "cherry"

RandomOrDefault([]string{}, "default") // Returns "default"

// Works with structs
type User struct {
    Name string
}
users := []User{{Name: "Alice"}, {Name: "Bob"}, {Name: "Charlie"}}
defaultUser := User{Name: "Unknown"}
RandomOrDefault(users, defaultUser) // Returns one of the users randomly

func Reduce added in v1.1.0

func Reduce[T any, R any](slice []T, initialValue R, reducer func(acc R, item T) R) R

Reduce applies a reducer function to each element in a slice, resulting in a single output value. It processes each element in the slice from left to right, accumulating a result.

Parameters:

  • slice: The input slice to reduce
  • initialValue: The initial value for the accumulator
  • reducer: A function that combines the accumulator with each element to produce a new accumulator value

Returns:

  • The final accumulated value

Example:

// Sum all numbers in a slice
Reduce([]int{1, 2, 3, 4}, 0, func(acc int, item int) int {
    return acc + item
}) // Returns 10

// Find the maximum value
Reduce([]int{5, 2, 8, 3}, math.MinInt, func(acc int, item int) int {
    if item > acc {
        return item
    }
    return acc
}) // Returns 8

// Concatenate strings
Reduce([]string{"Hello", " ", "World", "!"}, "", func(acc string, item string) string {
    return acc + item
}) // Returns "Hello World!"

// Transform a slice of structs into a map
type User struct {
    ID int
    Name string
}
users := []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
    {ID: 3, Name: "Charlie"},
}
userMap := Reduce(users, make(map[int]string), func(acc map[int]string, user User) map[int]string {
    acc[user.ID] = user.Name
    return acc
})
// Returns map[1:"Alice" 2:"Bob" 3:"Charlie"]

func Reverse

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

Reverse reverses the order of elements in array.

Parameters:

  • slice: The input array to reverse

Returns:

  • []T: A new array with elements in reverse order

Example:

Reverse([]int{1, 2, 3}) -> []int{3, 2, 1}
Reverse([]string{"a", "b", "c"}) -> []string{"c", "b", "a"}
Reverse([]int{1}) -> []int{1}

func Set added in v1.1.0

func Set(array map[string]any, key string, value any) map[string]any

Set sets a value within a nested map using "dot" notation.

Parameters:

  • array: The source map to modify
  • key: The key in dot notation (e.g., "user.address.city")
  • value: The value to set at the specified key

Returns:

  • A new map with the value set at the specified key

Example:

data := map[string]any{"user": map[string]any{"name": "John"}}
result := arr.Set(data, "user.age", 30)
// result: {"user": {"name": "John", "age": 30}}

func SetContains added in v1.1.0

func SetContains[T comparable](set map[T]struct{}, item T) bool

SetContains checks if a set (implemented as map[T]struct{}) contains a specific element.

Parameters:

  • set: The set to check
  • item: The element to look for

Returns:

  • true if the set contains the element, false otherwise

Example:

// Create a set
set := map[string]struct{}{
    "apple":  {},
    "banana": {},
    "cherry": {},
}

arr.SetContains(set, "banana") // Returns: true
arr.SetContains(set, "orange") // Returns: false

func SetDifference added in v1.1.0

func SetDifference[T comparable](set1, set2 map[T]struct{}) map[T]struct{}

SetDifference creates a new set containing elements that are in the first set but not in the second set.

Parameters:

  • set1: The first set (source set)
  • set2: The second set (elements to exclude)

Returns:

  • A new set containing elements that are in set1 but not in set2

Example:

set1 := map[string]struct{}{"a": {}, "b": {}, "c": {}}
set2 := map[string]struct{}{"b": {}, "c": {}, "d": {}}

difference := arr.SetDifference(set1, set2)
// difference: {"a": {}}

// Note that the difference is not symmetric:
difference2 := arr.SetDifference(set2, set1)
// difference2: {"d": {}}

func SetIntersection added in v1.1.0

func SetIntersection[T comparable](set1, set2 map[T]struct{}) map[T]struct{}

SetIntersection creates a new set containing only elements that exist in both input sets.

Parameters:

  • set1: The first set
  • set2: The second set

Returns:

  • A new set containing only elements that appear in both set1 and set2

Example:

set1 := map[string]struct{}{"a": {}, "b": {}, "c": {}}
set2 := map[string]struct{}{"b": {}, "c": {}, "d": {}}

intersection := arr.SetIntersection(set1, set2)
// intersection: {"b": {}, "c": {}}

Note:

  • The function optimizes performance by iterating over the smaller set

func SetToSlice added in v1.1.0

func SetToSlice[T comparable](set map[T]struct{}) []T

SetToSlice converts a set (implemented as map[T]struct{}) to a slice.

Parameters:

  • set: The set to convert

Returns:

  • A slice containing all elements from the set

Example:

// Create a set
set := map[string]struct{}{
    "apple":  {},
    "banana": {},
    "cherry": {},
}

slice := arr.SetToSlice(set)
// slice: []string{"apple", "banana", "cherry"} (order may vary)

func SetUnion added in v1.1.0

func SetUnion[T comparable](set1, set2 map[T]struct{}) map[T]struct{}

SetUnion creates a new set containing all elements from both input sets.

Parameters:

  • set1: The first set
  • set2: The second set

Returns:

  • A new set containing all elements that appear in either set1 or set2

Example:

set1 := map[string]struct{}{"a": {}, "b": {}, "c": {}}
set2 := map[string]struct{}{"b": {}, "c": {}, "d": {}}

union := arr.SetUnion(set1, set2)
// union: {"a": {}, "b": {}, "c": {}, "d": {}}

func Shuffle

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

Shuffle returns a new slice with elements in random order.

Parameters:

  • slice: The input array to shuffle

Returns:

  • []T: A new array with elements randomly reordered

Example:

Shuffle([]int{1, 2, 3, 4, 5}) -> [3, 1, 5, 2, 4]
Shuffle([]string{"a", "b", "c"}) -> ["c", "a", "b"]

func Slice

func Slice[T any](array []T, start, end int) []T

Slice returns a slice of array from start up to, but not including, end.

Parameters:

  • array: The input array
  • start: The starting index (inclusive)
  • end: The ending index (exclusive)

Returns:

  • []T: A new array containing elements from start index up to but not including end index

Example:

Slice([]int{1, 2, 3, 4}, 1, 3) -> []int{2, 3}
Slice([]string{"a", "b", "c", "d"}, 0, 2) -> []string{"a", "b"}
Slice([]int{1, 2, 3}, 2, 2) -> []int{}

func SliceToSet added in v1.1.0

func SliceToSet[T comparable](slice []T) map[T]struct{}

SliceToSet converts a slice to a set (implemented as map[T]struct{}). This is the inverse operation of SetToSlice.

Parameters:

  • slice: The slice to convert

Returns:

  • A set containing all unique elements from the slice

Example:

// Create a slice with duplicate elements
slice := []string{"apple", "banana", "apple", "cherry", "banana"}

set := arr.SliceToSet(slice)
// set: map[string]struct{}{"apple": {}, "banana": {}, "cherry": {}}
// Note: duplicates are automatically removed

func SortBy

func SortBy[T any, U int | int8 | int16 | int32 | int64 | float32 | float64 | string](array []T, iteratee func(T) U) []T

SortBy sorts an array by the results of running each element through the iteratee function. It returns a new sorted array without modifying the original.

Parameters:

  • array: The input array to be sorted
  • iteratee: A function that transforms each element into a comparable value

Returns:

  • A new sorted array

Example:

// Sort numbers in ascending order
SortBy([]int{1, 3, 2}, func(n int) int { return n }) // Returns [1, 2, 3]

// Sort strings by length
SortBy([]string{"apple", "banana", "kiwi"}, func(s string) int { return len(s) }) // Returns ["kiwi", "apple", "banana"]

// Sort structs by a specific field
type Person struct { Age int }
people := []Person{{Age: 30}, {Age: 25}, {Age: 40}}
SortBy(people, func(p Person) int { return p.Age }) // Returns [{Age: 25}, {Age: 30}, {Age: 40}]

func SortByKey added in v1.1.0

func SortByKey(array map[string]any) map[string]any

SortByKey sorts a map by keys in ascending alphabetical order.

Parameters:

  • array: The source map to sort

Returns:

  • A new map with keys sorted in ascending order

Example:

data := map[string]any{"c": 3, "a": 1, "b": 2}
result := arr.SortByKey(data)
// result: {"a": 1, "b": 2, "c": 3}

func SortByKeyDesc added in v1.1.0

func SortByKeyDesc(array map[string]any) map[string]any

SortByKeyDesc sorts a map by keys in descending alphabetical order.

Parameters:

  • array: The source map to sort

Returns:

  • A new map with keys sorted in descending order

Example:

data := map[string]any{"a": 1, "b": 2, "c": 3}
result := arr.SortByKeyDesc(data)
// result: {"c": 3, "b": 2, "a": 1}

func SortRecursive added in v1.1.0

func SortRecursive(array any) any

SortRecursive recursively sorts maps by keys and nested arrays/maps.

Parameters:

  • array: The source data structure to sort (can be a map, slice, or any other value)

Returns:

  • A new data structure with all nested maps sorted by keys

Example:

data := map[string]any{
    "c": 3,
    "a": map[string]any{"z": 26, "x": 24},
    "b": []any{2, 1, 3}
}
result := arr.SortRecursive(data)
// result: {
//   "a": {"x": 24, "z": 26},
//   "b": [2, 1, 3], // Note: array order is preserved
//   "c": 3
// }

func SortedCopy added in v1.1.0

func SortedCopy[T any](slice []T, less func(i, j T) bool) []T

SortedCopy returns a sorted copy of the slice without modifying the original. It uses the provided less function to determine the order.

Parameters:

  • slice: The input slice to be sorted
  • less: A function that returns true if element i should be ordered before element j

Returns:

  • A new sorted slice

Example:

// Sort integers in ascending order
SortedCopy([]int{3, 1, 4, 2}, func(i, j int) bool { return i < j })
// Returns [1, 2, 3, 4]

// Sort integers in descending order
SortedCopy([]int{3, 1, 4, 2}, func(i, j int) bool { return i > j })
// Returns [4, 3, 2, 1]

// Sort strings by length
SortedCopy([]string{"apple", "banana", "kiwi", "orange"}, func(i, j string) bool {
    return len(i) < len(j)
})
// Returns ["kiwi", "apple", "orange", "banana"]

// Sort structs by a specific field
type Person struct {
    Name string
    Age int
}
people := []Person{
    {Name: "Alice", Age: 30},
    {Name: "Bob", Age: 25},
    {Name: "Charlie", Age: 35},
}
// Sort by age
SortedCopy(people, func(i, j Person) bool { return i.Age < j.Age })
// Returns [{Name: "Bob", Age: 25}, {Name: "Alice", Age: 30}, {Name: "Charlie", Age: 35}]

func SortedIndex

func SortedIndex[T int | int8 | int16 | int32 | int64 | float32 | float64](array []T, value T) int

SortedIndex returns the index at which value should be inserted into array to maintain its sort order.

Parameters:

  • array: The sorted input array
  • value: The value to determine insertion index for

Returns:

  • int: The index at which the value should be inserted to maintain sort order

Example:

SortedIndex([]int{1, 3, 5, 7}, 4) -> 2
SortedIndex([]int{10, 20, 30, 40}, 25) -> 2
SortedIndex([]float64{1.5, 3.5, 5.5}, 0.5) -> 0

func Tail

func Tail[T any](array []T) []T

Tail returns all but the first element of array.

Parameters:

  • array: The input array

Returns:

  • []T: A new array containing all elements except the first one

Example:

Tail([]int{1, 2, 3}) -> []int{2, 3}
Tail([]string{"a", "b", "c"}) -> []string{"b", "c"}
Tail([]int{1}) -> []int{}

func Take

func Take[T any](array []T, n int) []T

Take creates a slice of array with n elements taken from the beginning.

Parameters:

  • array: The input array
  • n: Number of elements to take from the beginning

Returns:

  • []T: A new array with the first n elements

Example:

Take([]int{1, 2, 3, 4}, 2) -> []int{1, 2}
Take([]string{"a", "b", "c"}, 1) -> []string{"a"}
Take([]int{1, 2}, 3) -> []int{1, 2}

func TakeRight

func TakeRight[T any](array []T, n int) []T

TakeRight creates a slice of array with n elements taken from the end.

Parameters:

  • array: The input array
  • n: Number of elements to take from the end

Returns:

  • []T: A new array with the last n elements

Example:

TakeRight([]int{1, 2, 3, 4}, 2) -> []int{3, 4}
TakeRight([]string{"a", "b", "c"}, 1) -> []string{"c"}
TakeRight([]int{1, 2}, 3) -> []int{1, 2}

func Undot added in v1.1.0

func Undot(array map[string]any) map[string]any

Undot expands a flattened map with "dot" notation keys back into a nested map structure.

Parameters:

  • array: The flattened map with dot notation keys

Returns:

  • A new nested map structure

Example:

data := map[string]any{
    "user.name": "John",
    "user.address.city": "New York",
    "user.address.zip": "10001"
}
result := arr.Undot(data)
// result: {
//   "user": {
//     "name": "John",
//     "address": {
//       "city": "New York",
//       "zip": "10001"
//     }
//   }
// }

func Union

func Union[T comparable](arrays ...[]T) []T

Union creates an array of unique values from all given arrays.

Parameters:

  • arrays: Variable number of arrays to combine

Returns:

  • []T: A new array containing all unique elements from the input arrays

Example:

Union([]int{1, 2}, []int{2, 3}) -> []int{1, 2, 3}
Union([]string{"a", "b"}, []string{"b", "c"}, []string{"c", "d"}) -> []string{"a", "b", "c", "d"}
Union([]int{1, 1, 2}, []int{2, 2, 3}) -> []int{1, 2, 3}

func Uniq

func Uniq[T comparable](array []T) []T

Uniq creates an array of unique values.

Parameters:

  • array: The input array

Returns:

  • []T: A new array with duplicate elements removed

Example:

Uniq([]int{1, 2, 1, 3}) -> []int{1, 2, 3}
Uniq([]string{"a", "b", "a", "c", "b"}) -> []string{"a", "b", "c"}
Uniq([]int{1, 1, 1}) -> []int{1}

func Unique added in v1.1.0

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

Unique returns a new slice with duplicate elements removed. It preserves the order of elements, keeping the first occurrence of each element.

Parameters:

  • slice: The input slice that may contain duplicates

Returns:

  • A new slice with duplicate elements removed

Example:

// Remove duplicate integers
Unique([]int{1, 2, 2, 3, 1, 4, 5, 4}) // Returns [1, 2, 3, 4, 5]

// Remove duplicate strings
Unique([]string{"apple", "banana", "apple", "cherry", "banana"})
// Returns ["apple", "banana", "cherry"]

// Works with any comparable type
type User struct {
    ID int
    Name string
}
users := []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
    {ID: 1, Name: "Alice"}, // Duplicate
    {ID: 3, Name: "Charlie"},
    {ID: 2, Name: "Bob"},   // Duplicate
}
// Note: For structs, all fields must match for it to be considered a duplicate
uniqueUsers := Unique(users)
// Returns [{ID: 1, Name: "Alice"}, {ID: 2, Name: "Bob"}, {ID: 3, Name: "Charlie"}]

func WhereNotNull added in v1.1.0

func WhereNotNull[T any](array []T) []T

WhereNotNull filters an array by removing nil values.

Parameters:

  • array: The source array to filter

Returns:

  • A new array with all nil values removed

Example:

type User struct {
    Name string
}
var u1 = &User{Name: "Alice"}
var u2 *User = nil
var u3 = &User{Name: "Bob"}
users := []*User{u1, u2, u3}
result := arr.WhereNotNull(users)
// result: [&User{Name: "Alice"}, &User{Name: "Bob"}]

func Without

func Without[T comparable](array []T, values ...T) []T

Without creates an array excluding all given values.

Parameters:

  • array: The input array
  • values: Variable number of values to exclude from the array

Returns:

  • []T: A new array with all specified values excluded

Example:

Without([]int{1, 2, 3, 4}, 2, 4) -> []int{1, 3}
Without([]string{"a", "b", "c"}, "a", "c") -> []string{"b"}
Without([]int{1, 2, 3}, 4) -> []int{1, 2, 3}

func Wrap added in v1.1.0

func Wrap(value any) []any

Wrap ensures a value is contained in a slice. If the value is already a slice or array, it converts it to []any. Otherwise, it creates a new slice containing the value.

Parameters:

  • value: The value to wrap in a slice

Returns:

  • A slice containing the value or the converted slice

Example:

// Wrapping a single value
result1 := arr.Wrap(42)
// result1: []any{42}

// Wrapping an existing slice
nums := []int{1, 2, 3}
result2 := arr.Wrap(nums)
// result2: []any{1, 2, 3}

// Handling nil
result3 := arr.Wrap(nil)
// result3: []any{}

func Zip

func Zip[T any](arrays ...[]T) [][]T

Zip creates an array of grouped elements.

Parameters:

  • arrays: Variable number of arrays to zip together

Returns:

  • [][]T: A new array of arrays where each inner array contains elements from the input arrays at the same index

Example:

Zip([]int{1, 2}, []int{3, 4}) -> [][]int{{1, 3}, {2, 4}}
Zip([]string{"a", "b"}, []string{"c", "d"}, []string{"e", "f"}) -> [][]string{{"a", "c", "e"}, {"b", "d", "f"}}
Zip([]int{1, 2, 3}, []int{4, 5}) -> [][]int{{1, 4}, {2, 5}}

Types

This section is empty.

Jump to

Keyboard shortcuts

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