This is a Go implementation of sorted containers, inspired by the Python sortedcontainers library. The SortedList provides efficient insertion, deletion, and searching operations with O(log n) time complexity.
go get github.com/isdmx/sortedcontainers/sortedlistpackage main
import (
"fmt"
"github.com/isdmx/sortedcontainers/sortedlist"
)
func main() {
// Create a new sorted list
sl := sortedlist.New(3, 1, 4, 1, 5, 9, 2, 6)
fmt.Println(sl) // Output: SortedList([1 1 2 3 4 5 6 9])
// Add elements
sl.Add(0)
sl.Add(7)
fmt.Println(sl) // Output: SortedList([0 1 1 2 3 4 5 6 7 9])
// Check if element exists
fmt.Println(sl.Contains(5)) // Output: true
fmt.Println(sl.Contains(8)) // Output: false
// Get element by index
val, err := sl.At(5)
if err == nil {
fmt.Println(val) // Output: 5
}
// Remove element
removed := sl.Remove(5) // returns true if removed
fmt.Println(removed) // Output: true
fmt.Println(sl) // Output: SortedList([0 1 1 2 3 4 6 7 9])
}// Create empty sorted list
sl := sortedlist.New[int]()
// Add elements one by one
sl.Add(10)
sl.Add(5)
sl.Add(15)
sl.Add(5) // Duplicates allowed
fmt.Println(sl) // Output: SortedList([5 5 10 15])
// Update with multiple values at once
sl.Update([]int{1, 20, 8})
fmt.Println(sl) // Output: SortedList([1 5 5 8 10 15 20])
// Get length
fmt.Println(sl.Len()) // Output: 7
// Get element at index
val, _ := sl.At(0) // First element
fmt.Println(val) // Output: 1
// Get last element
val, _ = sl.At(-1)
fmt.Println(val) // Output: 20sl := sortedlist.New(1, 2, 3, 4, 5, 7, 8, 9)
// Find index of element
index := sl.IndexOf(5)
fmt.Println(index) // Output: 4
// Binary search operations
left := sl.BisectLeft(6) // Index to insert 6 to keep sorted order (on the left)
right := sl.BisectRight(6) // Index to insert 6 to keep sorted order (on the right)
fmt.Println(left, right) // Output: 5 5
// Count occurrences
sl.Add(5)
count := sl.Count(5)
fmt.Println(count) // Output: 2 (now there are 2 occurrences of 5)sl := sortedlist.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
// Get slice of elements (from index 2 to 7, exclusive)
start, stop := 2, 7
slice := sl.Slice(&start, &stop)
fmt.Println(slice) // Output: [2 3 4 5 6]
// Iterator over index range
for val := range sl.Islice(&start, &stop, false) {
fmt.Print(val, " ") // Output: 2 3 4 5 6
}
fmt.Println()
// Iterator over value range
min, max := 3, 7
for val := range sl.Irange(&min, &max, true, true, false) { // inclusive range [3,7]
fmt.Print(val, " ") // Output: 3 4 5 6 7
}
fmt.Println()
// Reverse iterator over value range
for val := range sl.Irange(&min, &max, true, true, true) { // reverse order
fmt.Print(val, " ") // Output: 7 6 5 4 3
}
fmt.Println()sl := sortedlist.New(1, 3, 5, 7, 9)
// Iterate through all elements
for val := range sl.All() {
fmt.Print(val, " ") // Output: 1 3 5 7 9
}
fmt.Println()
// Iterate in reverse
for val := range sl.Reversed() {
fmt.Print(val, " ") // Output: 9 7 5 3 1
}
fmt.Println()
// Get all values as slice
values := sl.Values()
fmt.Println(values) // Output: [1 3 5 7 9]sl := sortedlist.New(1, 2, 3, 4, 5)
// Remove element by value (returns true if found)
success := sl.Remove(3)
fmt.Println(success) // Output: true
// Remove element by index
val, err := sl.Pop(0) // Remove first element
if err == nil {
fmt.Println(val) // Output: 1
}
// Try remove that doesn't exist
success = sl.Remove(100)
fmt.Println(success) // Output: false
// Safe removal (no error if element doesn't exist)
sl.Discard(100) // No error even if not found
// Remove element with error if not found
err = sl.RemoveValue(2)
if err != nil {
fmt.Println("Error:", err)
}
// Get shallow copy
copied := sl.Copy()
fmt.Println(copied) // Copy of the sorted list
// Get index with bounds checking
index, err := sl.Index(4)
if err == nil {
fmt.Println("Index of 4:", index)
}sl := sortedlist.New(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
// Delete by index
err := sl.DeleteAt(0) // Remove first element
if err == nil {
fmt.Println("Deleted first element")
}
// Delete by index range
start, stop := 2, 5
err = sl.DeleteSlice(&start, &stop)
if err == nil {
fmt.Println("Deleted slice [2, 5)")
}
// Clear all elements
sl.Clear()
fmt.Println(sl.Len()) // Output: 0New[T cmp.Ordered](values ...T) *SortedList[T]- Creates a new sorted list with optional initial values
Add(value T)- Add value to sorted list in correct positionUpdate(values []T)- Add multiple values at onceCopy()- Create a shallow copy of the list
At(index int) (T, error)- Get element at index (supports negative indices)Len()- Get number of elementsValues()- Get all values as a sliceAll()- Iterator over all elementsReversed()- Iterator over all elements in reverse order
Contains(value T) bool- Check if value existsIndexOf(value T) int- Get first index of value (-1 if not found)Index(value T) (int, error)- Get index of value (errors if not found)Count(value T) int- Count occurrences of valueBisectLeft(value T) int- Index to insert keeping sorted order (left)BisectRight(value T) int- Index to insert keeping sorted order (right)Bisect(value T) int- Alias for BisectRight
Remove(value T) bool- Remove first occurrence (returns true if found)RemoveValue(value T) error- Remove first occurrence (errors if not found)Discard(value T)- Remove if present, no error if missingPop(index int) (T, error)- Remove and return element at indexDeleteAt(index int) error- Remove element at indexDeleteSlice(start, stop *int) error- Remove elements in index rangeClear()- Remove all elements
Slice(start, stop *int) []T- Get slice of elements by index rangeIslice(start, stop *int, reverse bool) iter.Seq[T]- Iterator by index rangeIrange(minimum, maximum *T, inclusiveLeft, inclusiveRight bool, reverse bool) iter.Seq[T]- Iterator by value range
String()- String representationAppend(value T) error- Raises error (not supported)Extend(values []T) error- Raises error (not supported)Insert(index int, value T) error- Raises error (not supported)Reverse() error- Raises error (not supported)
This project uses pre-commit hooks to ensure code quality and consistency. To set up pre-commit for this project:
-
Install pre-commit (if not already installed):
pip install pre-commit # or on macOS with Homebrew: brew install pre-commit -
Install the git hooks:
pre-commit install
-
The following checks will now run automatically before each commit:
- Go formatting and import organization
- Go linters and static analysis
- Code quality checks (cyclomatic complexity, security issues, etc.)
- File formatting (trailing whitespace, end of file, etc.)
- Go module tidying
- Unit tests execution
- Build validation
-
To run all checks manually on all files:
pre-commit run --all-files
To install required tools for development:
go mod tidy
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latestRun all tests:
go test ./...Run benchmarks:
go test -bench=. ./sortedlistRun tests with coverage:
go test -coverprofile=coverage.out ./sortedlist && go tool cover -func=coverage.outThe SortedList implementation provides the following time complexities:
- Add: O(log n) average
- Remove: O(log n) average
- Contains: O(log n)
- At/Pop: O(log n)
- Update: O(k log n) where k is number of new elements
- Count: O(log n + c) where c is count of element
sortedlist.go: Main SortedList implementationsortedlist_test.go: Core functionality testssortedlist_extra_test.go: Additional testssortedlist_new_methods_test.go: Tests for new methodssortedlist_final_coverage_test.go: Coverage-focused testssortedlist_bench_test.go: Benchmark tests