Slice is a Go package that provides a generic slice with extended functionality. It abstracts common list operations, such as appending, deleting, concatenating, mapping, and more, making it easier to work with slices in Go.
Slice simplifies the complexities of slice manipulation in Go, streamlining your code by offering a rich set of operations.
Incorporating Slice into your Go projects is effortless. Simply import the package, specify the type, and harness its capabilities right away.
Slice embraces generics, empowering you to store and slice data flexibly and efficiently.
Slice enhances code robustness by addressing common programming pitfalls, including null pointer dereferences and out-of-bounds array accesses. Your code stays safe and reliable.
You can install it in your Go project using go get
:
go get github.com/lindsaygelle/slice
Import the package into your Go code:
import (
"github.com/lindsaygelle/slice"
)
Provided methods for &slice.Slice[T]
.
Appends values to the end of the slice and returns a pointer to the modified slice.
newSlice := &slice.Slice[int]{}
newSlice.Append(1, 2)
fmt.Println(newSlice) // &[1, 2]
Appends selected elements to the end of the slice based on a provided condition.
newSlice := &slice.Slice[int]{}
values := []int{1, 2, 3, 4, 5}
newSlice.AppendFunc(values, func(i int, value int) bool {
return value%2 == 0
})
fmt.Println(newSlice) // &[2, 4]
Appends values to the end of the slice and returns the length of the modified slice.
newSlice := &slice.Slice[int]{}
length := newSlice.AppendLength(1, 2, 3)
fmt.Println(length) // 3
Checks if an index is within the valid range of indices for the slice.
newSlice := &slice.Slice[int]{1, 2, 3}
isWithinBounds := newSlice.Bounds(2)
fmt.Println(isWithinBounds) // true
Creates a duplicate of the current slice with a reference to a new pointer.
newSlice := &slice.Slice[int]{1, 2, 3}
cloneSlice := newSlice.Clone()
fmt.Println(cloneSlice) // &[1, 2, 3]
Merges elements from another slice to the tail of the receiver slice.
slice1 := &slice.Slice[int]{1, 2}
slice2 := &slice.Slice[int]{3, 4}
slice1.Concatenate(slice2)
fmt.Println(newSlice) // &[1, 2, 3, 4]
Appends elements from another slice based on a filtering function.
slice1 := &slice.Slice[int]{1, 2, 3}
slice2 := &slice.Slice[int]{4, 5, 6}
slice1.ConcatenateFunc(slice2, func(i int, value int) bool {
return value%2 == 0
})
fmt.Println(slice1) // &[2, 4, 6]
Merges elements from another slice to the tail of the receiver slice and returns the length of the modified slice.
slice1 := &slice.Slice[int]{1, 2}
slice2 := &slice.Slice[int]{3, 4}
length := slice1.ConcatenateLength(slice2)
fmt.Println(length) // 4
Checks if a value exists in the slice.
newSlice := &slice.Slice[int]{1, 2, 3}
contains := slice.Contains(2)
fmt.Println(contains) // true
Checks if multiple values exist in the slice and returns a boolean slice indicating their presence.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
contains := slice.ContainsMany(2, 6)
fmt.Println(contains) // &[true, false]
Removes values from the slice that have the same basic hash value.
newSlice := &slice.Slice[int]{1, 2, 2, 3, 4, 4, 5}
slice.Deduplicate()
fmt.Println(newSlice) // &[1, 2, 3, 4, 5]
Safely removes an element from the slice by index.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice := slice.Delete(2)
fmt.Println(newSlice) // &[1, 2, 4, 5]
Safely removes elements from the slice based on a provided predicate function.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.DeleteFunc(func(i int, value int) bool {
return value%2 == 0
})
fmt.Println(newSlice) // &[1, 3, 5]
Safely removes an element from the slice by index and returns the new length of the modified slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
length := slice.DeleteLength(2)
fmt.Println(length) // 4
Safely removes an element from the slice by index and returns a boolean indicating the success of the operation.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
success := slice.DeleteOK(2)
fmt.Println(success) // true
Removes an element from the slice by index. Panics if index is out of bounds.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.DeleteUnsafe(2)
fmt.Println(newSlice) // &[1, 2, 4, 5]
Executes a provided function for each element in the slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.Each(func(i int, value int) {
fmt.Println(value)
})
// Output:
// 1
// 2
// 3
// 4
// 5
Executes a provided function for each element in the slice with an optional break condition.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.EachBreak(func(i int, value int) bool {
fmt.Println(value)
return value == 3
})
// Output:
// 1
// 2
// 3
Executes a provided function for each element in the slice and returns a bool breaking the loop when true.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
allPositive := slice.EachOK(func(i int, value int) bool {
return value > 0
})
fmt.Println(allPositive) // true
Executes a provided function for each element in reverse order.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.EachReverse(func(i int, value int) {
fmt.Println(value)
})
// Output:
// 5
// 4
// 3
// 2
// 1
Executes a provided function for each element in reverse order with an optional break condition.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.EachReverseBreak(func(i int, value int) bool {
fmt.Println(value)
return value == 3
})
// Output:
// 5
// 4
// 3
Executes a provided function for each element in the slice and returns a bool breaking the loop when true.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
allPositive := slice.EachReverseOK(func(i int, value int) bool {
return value > 0
})
fmt.Println(allPositive) // true
Checks if the two slices are equal.
slice1 := &slice.Slice[int]{1, 2, 3}
slice2 := &slice.Slice[int]{1, 2, 3}
isEqual := slice1.Equal(slice2)
fmt.Println(isEqual) // true
Checks whether the slices are equal based on the filtering function.
slice1 := &slice.Slice[int]{1, 2, 3}
slice2 := &slice.Slice[int]{2, 3, 4}
isEqual := slice1.EqualFunc(slice2, func(i int, a int, b int) bool {
return a == b-1
})
fmt.Println(isEqual) // true
Checks if the two slices have the same length.
slice1 := &slice.Slice[int]{1, 2, 3}
slice2 := &slice.Slice[int]{4, 5, 6}
isEqualLength := slice1.EqualLength(slice2)
fmt.Println(isEqualLength) // true
Retrieves the element at a specified index in the slice.
newSlice := &slice.Slice[int]{1, 2, 3}
value := slice.Fetch(1)
fmt.Println(value) // 2
Retrieves the element at a specified index in the slice and the length of the slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
value, length := slice.FetchLength(2)
fmt.Println(value, length) // 3, 5
Creates a new slice containing elements that satisfy a given predicate function.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
filteredSlice := slice.Filter(func(i int, value int) bool {
return value%2 == 0
})
fmt.Println(filteredSlice) // &[2, 4]
Finds the index of the first element that satisfies a given predicate function.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
index, found := slice.FindIndex(func(value int) bool {
return value == 3
})
fmt.Println(index, found) // 2, true
Retrieves the element at a specified index in the slice and returns a boolean indicating success.
newSlice := &slice.Slice[int]{1, 2, 3}
value, found := slice.Get(1)
fmt.Println(value, found) // 2, true
Retrieves the element at a specified index in the slice, a boolean indicating success and the length of the slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
value, found, length := slice.GetLength(2)
fmt.Println(value, found, length) // 3, true, 5
Checks if the slice is empty.
newSlice := &slice.Slice[int]{}
isEmpty := newSlice.IsEmpty()
fmt.Println(isEmpty) // true
Checks if the slice is not empty.
newSlice := &slice.Slice[int]{1, 2, 3}
isPopulated := newSlice.IsPopulated()
fmt.Println(isPopulated) // true
Returns the number of elements in the slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
length := slice.Length()
fmt.Println(length) // 5
Empties the slice and sets it to a specified length.
newSlice := (&slice.Slice[int]{}).Make(3)
fmt.Println(newSlice) // &[0, 0, 0]
Empties the slice, sets it to a specified length, and populates it with provided values.
newSlice := (&slice.Slice[int]{}).MakeEach(1, 2, 3)
fmt.Println(newSlice) // &[1, 2, 3]
Empties the slice, sets it to a specified length, and populates it with provided values in reverse order.
newSlice := (&slice.Slice[int]{}).MakeEachReverse(1, 2, 3)
fmt.Println(newSlice) // &[3, 2, 1]
Executes a provided function for each element and sets the returned value to a new slice at the current index.
newSlice := &slice.Slice[int]{1, 2, 3}
mappedSlice := slice.Map(func(i int, value int) int {
return value * 2
})
fmt.Println(mappedSlice) // &[2, 4, 6]
Executes a provided function for each element in reverse order and sets the returned value to a new slice at the current index.
newSlice := &slice.Slice[int]{1, 2, 3}
mappedSlice := slice.MapReverse(func(i int, value int) int {
return value * 2
})
fmt.Println(mappedSlice) // &[6, 4, 2]
Modify applies the provided function to each element in the slice and modifies the elements in place.
newSlice := &slice.Slice[int]{1, 2, 3}
newSlice.Modify(func(i int, value int) int {
return value + 10
})
fmt.Println(slice) // &[11, 12, 13]
Modify applies the provided function to each element in the slice in reverse order and modifies the elements in place.
newSlice := &slice.Slice[int]{1, 2, 3}
newSlice.ModifyReverse(func(i int, value int) int {
return value + 10
})
fmt.Println(slice) // &[13, 12, 11]
Removes and returns the first element from the slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
value := slice.Poll()
fmt.Println(value) // 1
Removes the first element from the slice and returns the removed element and the length of the modified slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
value, length := slice.PollLength()
fmt.Println(value, length) // 1, 4
Removes and returns the first element from the slice and returns a boolean indicating success.
newSlice := &slice.Slice[int]{1, 2, 3}
value, ok := slice.PollOK()
fmt.Println(value, ok) // 1, true
Removes and returns the last element from the slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
value := slice.Pop()
fmt.Println(value) // 5
Removes the last element from the slice and returns the removed element and the length of the modified slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
value, length := slice.PopLength()
fmt.Println(value, length) // 5, 4
Removes and returns the last element from the slice and returns a boolean indicating success.
newSlice := &slice.Slice[int]{1, 2, 3}
value, ok := slice.PopOK()
fmt.Println(value, ok) // 3, true
Merges elements from another slice to the head of the receiver slice.
slice1 := &slice.Slice[int]{1, 2}
slice2 := &slice.Slice[int]{3, 4}
slice1.Precatenate(slice2)
fmt.Println(slice1) // &[1, 2, 3, 4]
Prepends elements from another slice based on a provided predicate function.
slice1 := &slice.Slice[int]{1, 2, 3}
slice2 := &slice.Slice[int]{3, 4, 5}
slice1.PrecatenateFunc(slice2, func(i int, value int) bool {
return value%2 == 0
})
fmt.Println(slice1) // &[2, 4]
Merges elements from another slice to the head of the receiver slice and returns the length of the modified slice.
slice1 := &slice.Slice[int]{1, 2}
slice2 := &slice.Slice[int]{3, 4}
length := slice1.PrecatenateLength(slice2)
fmt.Println(length) // 4
Adds one element to the head of the slice.
newSlice := &slice.Slice[int]{3, 4, 5}
newSlice.Prepend(1, 2)
fmt.Println(newSlice) // &[1, 2, 3, 4, 5]
Prepends elements to the head of the slice based on a provided predicate function.
newSlice := &slice.Slice[int]{3, 4, 5}
values := []int{1, 2}
slice.PrependFunc(values, func(i int, value int) bool {
return value%2 == 0
})
fmt.Println(newSlice) // &[2, 4, 3, 4, 5]
Adds multiple elements to the head of the slice and returns the length of the modified slice.
newSlice := &slice.Slice[int]{3, 4, 5}
length := newSlice.PrependLength(1, 2)
fmt.Println(length) // 5
Reduce applies the provided function to each element in the slice and reduces the elements to a single value.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
result := newSlice.Reduce(func(i int, currentValue int, resultValue int) int {
return resultValue + currentValue
})
fmt.Println(result) // 15
ReduceReverse iterates over the slice in reverse order and reduces the elements into a single value using the provided function.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
result := newSlice.ReduceReverse(func(i int, currentValue int, resultValue int) int {
return resultValue + currentValue
})
fmt.Println(result) // 15
Replaces the element at the index with the provided value.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
success := slice.Replace(2, 10)
fmt.Println(slice) // &[1, 2, 10, 4, 5]
fmt.Println(success) // true
Reverses the order of the slice.
newSlice := &slice.Slice[int]{1, 2, 3}
newSlice.Reverse()
fmt.Println(newSlice) // &[3, 2, 1]
Randomly shuffles elements in the slice.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.Shuffle()
fmt.Println(newSlice) // Randomly shuffled slice
Creates a subset of the values based on the beginning and end index.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
subSlice := newSlice.Slice(1, 4)
fmt.Println(subSlice) // &[2, 3, 4]
Sorts elements in the slice that satisfy a provided predicate function.
newSlice := &slice.Slice[int]{5, 2, 1, 4, 3}
newSlice.SortFunc(func(i int, j int, a int, b int) bool {
return a < b
})
fmt.Println(newSlice) // &[1, 2, 3, 4, 5]
Modifies the slice to include only the values based on the beginning and end index.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
splicedSlice := newSlice.Splice(1, 3)
fmt.Println(splicedSlice) // &[2, 3]
Divides the slice into two slices at the specified index and returns the two new slices.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
left, right := newSlice.Split(2)
fmt.Println(left, right) // &[1, 2], &[3, 4, 5]
Divides the slice into two slices based on the provided function and returns the two new slices.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
left, right := newSlice.SplitFunc(func(i int, value int) bool {
return value > 2
})
fmt.Println(left, right) // &[1, 2], &[3, 4, 5]
Divides the slice into two slices at the specified index and returns the two new slices, or false if the index is invalid.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
left, right, exists := newSlice.SplitOK(2)
fmt.Println(left, right, exists) // &[1, 2], &[3, 4, 5], true
Swaps values at indexes i and j.
newSlice := &slice.Slice[int]{1, 2, 3, 4, 5}
newSlice.Swap(0, 4)
fmt.Println(newSlice) // &[5, 2, 3, 4, 1]
// Define a custom struct.
type Person struct {
Name string
Age int
Email string
}
// Create a slice of Person structs.
people := &slice.Slice[Person]{
{Name: "Alice", Age: 30, Email: "[email protected]"},
{Name: "Bob", Age: 25, Email: "[email protected]"},
}
// Append a new person to the slice.
newPerson := Person{Name: "Charlie", Age: 35, Email: "[email protected]"}
people.Append(newPerson)
// Find the index of a person with a specific email address.
index := people.FindIndex(func(p Person) bool {
return p.Email == "[email protected]"
})
// Slice the slice to include only people aged 30 or older.
people.Slice(1, people.Length())
// Reverse the order of people in the slice.
people.Reverse()
// Iterate over the slice and print each person's details.
people.Each(func(index int, person Person) {
fmt.Printf("Index %d: Name: %s, Age: %d, Email: %s\n", index, person.Name, person.Age, person.Email)
})
s := (&slice.Slice[int64]{1, 2, 3}).Append(4, 5, 6).Filter(func(_ int, value int64) bool {
return value%2 == 0
})
fmt.Println(s) // 2, 4, 6.
A Dockerfile is provided for individuals that prefer containerized development.
Building the Docker container:
docker build . -t slice
Developing and running Go within the Docker container:
docker run -it --rm --name slice slice
A docker-compose file has also been included for convenience:
Running the compose file.
docker-compose up -d
We warmly welcome contributions to Slice. Whether you have innovative ideas, bug reports, or enhancements in mind, please share them with us by submitting GitHub issues or creating pull requests. For substantial contributions, it's a good practice to start a discussion by creating an issue to ensure alignment with the project's goals and direction. Refer to the CONTRIBUTING file for comprehensive details.
For a smooth collaboration experience, we have established branch naming conventions and guidelines. Please consult the BRANCH_NAMING_CONVENTION document for comprehensive information and best practices.
Slice is released under the MIT License, granting you the freedom to use, modify, and distribute the code within this repository in accordance with the terms of the license. For additional information, please review the LICENSE file.
If you discover a security vulnerability within this project, please consult the SECURITY document for information and next steps.
This project has adopted the Amazon Open Source Code of Conduct. For additional information, please review the CODE_OF_CONDUCT file.
Big thanks to egonelbre/gophers for providing the delightful Gopher artwork used in the social preview. Don't hesitate to pay them a visit!