slice

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2024 License: MIT Imports: 1 Imported by: 0

README

Go Reference Tests Coverage Status Go Report Card

slice

A simple, generic, and easy-to-use Go library that provides a rich set of utility functions for managing and manipulating slices. It wraps native slices and offers an intuitive API for performing common operations such as adding, removing, filtering, and modifying elements.

Features

  • Simple and Intuitive Syntax: Easy-to-use methods for operations like push, pop, and insertion.
  • Flexible Types: Works with any type of slice thanks to Go’s generics.
  • Advanced Operations: Support for advanced functionality like filtering, sorting, shuffling, and reversing.
  • Safe Indexing: Support for negative indexes and index-bounds checks.

Performance Characteristics

  • No Extra Allocations: This library is designed to avoid unnecessary memory allocations. Operations like shifting, popping, deleting, or inserting elements reuse the existing slice capacity wherever possible. This helps optimize memory usage and keeps performance consistent, especially in tight loops or high-frequency operations.
  • Memory Zeroing: When elements are deleted, shifted, or popped, the library automatically "zeroes out" the removed elements by setting them to the zero value of their type. This prevents potential memory leaks and ensures that the garbage collector can efficiently clean up unused elements.

Installation

go get github.com/go-slice/slice

Usage Examples

Creating a Slice

There are multiple ways to create a slice, either with or without predefined elements:

Using an Empty Slice

To create an empty slice of integers:

package main

import (
    "fmt"

    "github.com/go-slice/slice"
)

func main() {
    // Create an empty slice
    var s slice.Slice[int]

    // Add some elements
    s.Push(4, 5, 6)
    
    fmt.Println(s)  // Output: [4 5 6]
}
Initializing with Elements

You can also initialize the slice with elements using the following syntax:

// Create a slice with predefined elements
s := slice.Slice[int]{4, 5, 6}
fmt.Println(s)  // Output: [4 5 6]
Creating with Predefined Capacity

To create a slice with a predefined capacity (which can help avoid redundant allocations when you know the size in advance):

// Create a slice with a capacity of 100 but no initial elements
s := slice.FromRaw(make([]int, 0, 100))

// Now you can add elements without triggering new allocations until the slice exceeds the capacity
s.Push(1, 2, 3)
fmt.Println(s)  // Output: [1 2 3]
Basic Operations
Push and Pop

Append or remove elements from the end of the slice.

var s slice.Slice[int]

// Push 3 elements to the slice
s.Push(10, 20, 30)
fmt.Println(s)  // Output: [10 20 30]

// Pop the last element
val, _ := s.Pop()
fmt.Println(val)  // Output: 30
fmt.Println(s)    // Output: [10 20]
Unshift and Shift

Add or remove elements from the beginning of the slice.

var s slice.Slice[int]

// Push elements to the slice
s.Push(3, 4, 5)

// Unshift adds elements to the beginning of the slice
s.Unshift(1, 2)
fmt.Println(s)  // Output: [1 2 3 4 5]

// Shift removes the first element and returns it
val, _ := s.Shift()
fmt.Println(val)  // Output: 1
fmt.Println(s)    // Output: [2 3 4 5]
Deleting Elements
Delete a Single Element

You can delete a single element from any position in the slice. For example, deleting the element at index 2:

var s slice.Slice[int]

// Push elements to the slice
s.Push(1, 2, 3, 4, 5)

// Delete 1 element starting at index 2
s.Delete(2, 1)
fmt.Println(s)  // Output: [1 2 4 5]
Delete the Last Element

You can use a negative index to delete the last element. This can be done using s.Delete(-1, 1) or s.DeleteOne(-1), as both are equivalent when removing the last element:

var s slice.Slice[int]

// Push elements to the slice
s.Push(1, 2, 3, 4, 5)

// Delete 1 element starting from the last index (-1)
s.Delete(-1, 1)
fmt.Println(s)  // Output: [1 2 3 4]

// Alternatively, delete the last element with DeleteOne
s.DeleteOne(-1)
Modifying the Slice
Insert

Insert elements at a specific index.

var s slice.Slice[string]

// Push initial elements to the slice
s.Push("one", "three")

// Insert "two" at index 1
s.Insert(1, "two")
fmt.Println(s)  // Output: [one two three]
Replace

Replace a section of the slice with new elements.

var s slice.Slice[string]

// Push elements to the slice
s.Push("a", "b", "b", "b", "e")

// Replace the slice from index 2 with "c" and "d"
s.Replace(2, "c", "d")
fmt.Println(s)  // Output: [a b c d e]
Advanced Operations
Filter

Remove elements based on a custom condition.

var s slice.Slice[int]

// Push elements to the slice
s.Push(1, 2, 3, 4, 5, 6)

// Keep only even numbers using the Filter method
s.Filter(func(_ int, v int) bool {
    return v%2 == 0
})
fmt.Println(s)  // Output: [2 4 6]
Reverse

Reverse the order of elements in the slice.

var s slice.Slice[int]

// Push elements to the slice
s.Push(1, 2, 3, 4, 5)

// Reverse the order of the slice
s.Reverse()
fmt.Println(s)  // Output: [5 4 3 2 1]
Sort

Sort the slice using a custom comparison function.

var s slice.Slice[int]

// Push elements to the slice
s.Push(5, 3, 1, 4, 2)

// Sort the slice in ascending order
s.Sort(func(a, b int) int {
    return a - b
})
fmt.Println(s)  // Output: [1 2 3 4 5]
Shuffle

Randomly shuffle the elements in the slice.

import "math/rand"

var s slice.Slice[int]

// Push elements to the slice
s.Push(1, 2, 3, 4, 5)

// Shuffle the slice using a random integer generator
s.Shuffle(rand.Intn)
fmt.Println(s)  // Output: [3 5 1 4 2] (shuffled randomly)
Safe Indexing
Get with Negative Indexes

Get an element using a negative index, counting from the end.

var s slice.Slice[int]

// Push elements to the slice
s.Push(1, 2, 3, 4, 5)

// Get the last element using a negative index (-1)
val, _ := s.Get(-1)
fmt.Println(val)  // Output: 5
Other Utility Methods
  • Clone(): Create a copy of the slice.
  • Len(): Get the length of the slice.
  • Cap(): Get the capacity of the slice.
  • Empty(): Check if the slice is empty.

License

This project is licensed under the MIT License.


Feel free to use, modify, and contribute!

Documentation

Overview

Package slice provides a toolset to manipulate slices.

var s slice.Slice[int]
s.Push(4, 5, 6)    // [4 5 6]
s.Unshift(1, 2, 3) // [1 2 3 4 5 6]
s.Pop()            // [1 2 3 4 5]
Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	var s slice.Slice[int]

	s.Push(4, 5, 6)
	s.Unshift(1, 2, 3)
	s.DeleteOne(0)
	s.Pop()

	fmt.Println(s)

}
Output:

[2 3 4 5]

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Slice

type Slice[T any] []T

Slice is a wrapper of any slice that allows performing basic operations over slices using an intuitive syntax.

var s slice.Slice[int]
s.Push(4, 5, 6)    // [4 5 6]
s.Unshift(1, 2, 3) // [1 2 3 4 5 6]
s.Pop()            // [1 2 3 4 5]

func FromRaw

func FromRaw[T any](in []T) Slice[T]

FromRaw creates a new Slice.

func (*Slice[T]) Cap

func (s *Slice[T]) Cap() int

Cap returns the capacity of the given slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s1 := slice.Slice[int](nil)
	s2 := slice.FromRaw(make([]int, 0, 100))

	fmt.Println(s1.Cap())
	fmt.Println(s2.Cap())

}
Output:

0
100

func (*Slice[T]) Clone

func (s *Slice[T]) Clone() Slice[T]

Clone returns a new slice with the same length and copies to it all the elements from the existing slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	original := make([]int, 2, 10)
	original[0] = 1
	original[1] = 2

	s := slice.FromRaw(original)

	clone := s.Clone()

	// modify the original slice
	s.DeleteOne(1)
	s.Push(5)

	fmt.Println(original)
	fmt.Println(clone) // clone remains unchanged

}
Output:

[1 5]
[1 2]
Example (Nil)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw[int](nil)
	fmt.Println(s.Clone() == nil)

}
Output:

true

func (*Slice[T]) Delete

func (s *Slice[T]) Delete(index int, length int) (ok bool)

Delete deletes a vector of the given length under the given index from the given slice.

s := slice.FromRaw([]int{1, 2, 3, 4, 5})
s.Delete(1, 3)
fmt.Println(s) [1 5]
Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]string{"one", "two", "three", "four", "five", "six"})
	fmt.Println(s.Delete(0, 1)) // [two three four five six]
	fmt.Println(s.Delete(4, 1)) // [two three four five]
	fmt.Println(s.Delete(1, 2)) // [two five]
	fmt.Println(s.Delete(0, 3)) // [two five] - do nothing, invalid input
	fmt.Println(s)

}
Output:

true
true
true
false
[two five]
Example (Last)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{1, 2, 3, 4, 5})
	s.Delete(-1 /* index */, 1 /* length */)

	fmt.Println(s)

}
Output:

[1 2 3 4]

func (*Slice[T]) DeleteOne

func (s *Slice[T]) DeleteOne(index int) (ok bool)

DeleteOne deletes a single element from the given slice.

s.DeleteOne(index) // it's an equivalent of s.Delete(index, 1)
Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]string{"one", "two", "three"})
	fmt.Println(s.DeleteOne(3)) // no element under the index 3
	fmt.Println(s.DeleteOne(1))
	fmt.Println(s)

}
Output:

false
true
[one three]

func (*Slice[T]) Empty

func (s *Slice[T]) Empty() bool

Empty returns false when the len of the given slice equals 0.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s1 := slice.FromRaw(make([]int, 0))
	s2 := slice.Slice[int](nil)
	s3 := slice.Slice[int]([]int{1})

	s3.Pop()

	fmt.Println(s1.Empty())
	fmt.Println(s2.Empty())
	fmt.Println(s3.Empty())

}
Output:

true
true
true

func (*Slice[T]) Filter

func (s *Slice[T]) Filter(keep func(index int, val T) bool)

Filter filters the given slice using the provided func.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	x := slice.FromRaw([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
	x.Filter(func(_ int, val int) bool {
		return val%2 == 0
	})

	fmt.Println(x)

}
Output:

[2 4 6 8 10]
Example (Nil)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	x := slice.FromRaw[int](nil)
	x.Filter(func(index int, val int) bool { // do nothing
		return true
	})
	fmt.Println(x.Raw() == nil)

}
Output:

true

func (*Slice[T]) Get

func (s *Slice[T]) Get(index int) (_ T, ok bool)

Get returns an element under the given index. It accepts negative indexes.

x := slice.FromRaw([]int{1, 2, 3, 4, 5})
val, ok := x.Get(-1)
fmt.Println(val) // 5
Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	x := slice.FromRaw([]int{1, 2, 3, 4, 5})
	fmt.Println(x.Get(0))  // 1 true
	fmt.Println(x.Get(4))  // 5 true
	fmt.Println(x.Get(-1)) // 5 true
	fmt.Println(x.Get(-5)) // 1 true
	fmt.Println(x.Get(-6)) // 0 false
	fmt.Println(x.Get(5))  // 0 false

}
Output:

1 true
5 true
5 true
1 true
0 false
0 false

func (*Slice[T]) Insert

func (s *Slice[T]) Insert(index int, v ...T) (ok bool)

Insert inserts the given element to the existing slice under the given index.

s := slice.FromRaw([]string{"one", "four"})
s.Insert(1 "two", "three")
fmt.Println(s) // ["one", "two", "three", "four"]
Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]string{"one", "four"})
	s.Insert(1, "two", "three")
	fmt.Println(s)

}
Output:

[one two three four]
Example (False)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw[string](nil)
	fmt.Println(s.Insert(1, "one")) // the highest possible index to insert == len(s)

	s = slice.FromRaw([]string{"zero", "one", "two"})
	fmt.Println(s.Insert(-100, "minus one")) // invalid index

}
Output:

false
false

func (*Slice[T]) Len

func (s *Slice[T]) Len() int

Len returns the length of the given slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s1 := slice.Slice[int](nil)
	s2 := slice.FromRaw(make([]int, 100))

	fmt.Println(s1.Len())
	fmt.Println(s2.Len())

}
Output:

0
100

func (*Slice[T]) Pop

func (s *Slice[T]) Pop() (_ T, ok bool)

Pop returns the last element and removes it from the given slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{1, 2})
	fmt.Println(s.Pop())
	fmt.Println(s.Pop())
	fmt.Println(s.Pop())

}
Output:

2 true
1 true
0 false

func (*Slice[T]) Push

func (s *Slice[T]) Push(v ...T)

Push appends the given input to the given slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{1, 2})
	s.Push(3)
	s.Push(4, 5)
	fmt.Println(s)

}
Output:

[1 2 3 4 5]
Example (Nil)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw[int](nil)
	s.Push(1, 2, 3)
	fmt.Println(s)

}
Output:

[1 2 3]

func (*Slice[T]) Raw

func (s *Slice[T]) Raw() []T

Raw returns the underlying slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	data := []int{1, 2, 3}
	s := slice.Slice[int](data)

	fmt.Println(s.Raw())
}
Output:

[1 2 3]
Example (Nil)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.Slice[int](nil)
	fmt.Println(s.Raw() == nil)

}
Output:

true

func (*Slice[T]) Replace

func (s *Slice[T]) Replace(index int, v ...T) (ok bool)

Replace replaces s[index:index+len(v)] with v. It does not succeed when the given slice does not have enough elements to be replaced.

s := slice.FromRaw([]string{"one", "two", "two", "two", "two"})
s.Replace(2, "three", "four", "five")
fmt.Println(s) // [one two three four five]
Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]string{"one", "two", "two", "two", "two"})
	s.Replace(2, "three", "four", "five")
	fmt.Println(s)

}
Output:

[one two three four five]
Example (False)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]string{"one", "two", "two", "two"})

	// cannot replace 3 elements starting from index 2
	// the given slice does not have enough elements
	fmt.Println(s.Replace(2, "three", "four", "five"))
	fmt.Println(s)

}
Output:

false
[one two two two]
Example (Last)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{1, 2, 3, 4, 4})
	s.Replace(-1, 5)
	fmt.Println(s)

}
Output:

[1 2 3 4 5]

func (*Slice[T]) Reverse

func (s *Slice[T]) Reverse()

Reverse reverses order of the given slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{5, 4, 3, 2, 1})
	s.Reverse()
	fmt.Println(s)

}
Output:

[1 2 3 4 5]

func (*Slice[T]) Shift

func (s *Slice[T]) Shift() (_ T, ok bool)

Shift returns the first element and removes it from the given slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{1, 2, 3})
	fmt.Println(s.Shift())
	fmt.Println(s)

}
Output:

1 true
[2 3]
Example (Nil)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.Slice[int](nil)
	fmt.Println(s.Shift())

}
Output:

0 false

func (*Slice[T]) Shuffle

func (s *Slice[T]) Shuffle(randIntN func(n int) int)

Shuffle shuffles the given input. randIntN must generate a pseudo-random number in the half-open interval [0,n).

s := slice.FromRaw([]int{1, 2, 3, 4, 5})
s.Shuffle(rand.Intn)
Example
package main

import (
	"fmt"
	"math/rand"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{1, 2, 3, 4, 5})
	s.Shuffle(rand.Intn)
	fmt.Println(s) // e.g. [3 1 5 4 2]
}

func (*Slice[T]) Sort

func (s *Slice[T]) Sort(cmp func(a T, b T) int)

Sort sorts the given slice in ascending order as determined by the cmp function. It requires that cmp is a strict weak ordering. See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{3, 2, 5, 4, 1})
	s.Sort(func(a int, b int) int {
		return a - b
	})
	fmt.Println(s)

}
Output:

[1 2 3 4 5]
Example (Nil)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	var s slice.Slice[int]
	s.Sort(func(a int, b int) int { // do nothing, there is nothing to sort
		return a - b
	})
	fmt.Println(s.Raw() == nil)

}
Output:

true

func (*Slice[T]) Unshift

func (s *Slice[T]) Unshift(v ...T)

Unshift prepends the given input to the given slice.

Example
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw([]int{4, 5, 6})
	s.Unshift(2, 3)
	s.Unshift(1)
	s.Unshift() // do nothing

	fmt.Println(s)

}
Output:

[1 2 3 4 5 6]
Example (Nil)
package main

import (
	"fmt"

	"github.com/go-slice/slice"
)

func main() {
	s := slice.FromRaw[int](nil)
	s.Unshift(1, 2, 3)

	fmt.Println(s)

}
Output:

[1 2 3]

Jump to

Keyboard shortcuts

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