The slices.SortStableFunc function in Golang is part of the slices package, introduced in Go 1.21 as part of the standard library. This function allows you to sort the elements of a slice in place using a custom comparison function, while maintaining the relative order of equal elements. This stable sorting behavior is particularly useful when the original order of equivalent elements matters.
Table of Contents
- Introduction
slices.SortStableFuncFunction Syntax- Examples
- Basic Usage
- Sorting a Slice of Structs with Stable Sorting
- Custom Stable Sorting for Complex Types
- Real-World Use Case Example
- Conclusion
Introduction
The slices.SortStableFunc function provides a stable sorting mechanism that preserves the relative order of elements that compare as equal. This is particularly useful in scenarios where the input data has a natural order that should be maintained for equal elements, such as when sorting by a primary key while keeping the original order of secondary keys.
slices.SortStableFunc Function Syntax
The syntax for the slices.SortStableFunc function is as follows:
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int)
Parameters:
x S: The slice to be sorted.cmp func(a, b E) int: A custom comparison function that defines the sorting order. It should return:- A negative number if
ashould come beforeb. - Zero if
aandbare considered equal. - A positive number if
ashould come afterb.
- A negative number if
Returns:
void: This function does not return a value; it modifies the slice in place.
Behavior:
- Stable in-place sorting: The function sorts the elements in the slice
xin place according to the custom comparison logic defined by thecmpfunction, while preserving the relative order of equal elements.
Examples
Basic Usage
This example demonstrates how to use slices.SortStableFunc to sort a slice of integers while maintaining the relative order of equal elements.
Example
package main
import (
"fmt"
"slices"
)
func main() {
// Define a slice of integers with repeated elements
numbers := []int{5, 3, 4, 1, 2, 3, 5}
// Define a custom comparison function for ascending order
compareAscending := func(a, b int) int {
return a - b
}
// Sort the slice in ascending order with stable sorting
slices.SortStableFunc(numbers, compareAscending)
// Print the sorted slice
fmt.Println("Stably sorted slice:", numbers)
}
Output:
Stably sorted slice: [1 2 3 3 4 5 5]
Explanation:
- The
slices.SortStableFuncfunction sorts thenumbersslice in ascending order while maintaining the relative order of the repeated elements (3and5).
Sorting a Slice of Structs with Stable Sorting
This example shows how to use slices.SortStableFunc to sort a slice of structs by a specific field while preserving the relative order of elements with equal values.
Example
package main
import (
"fmt"
"slices"
)
type Person struct {
Name string
Age int
}
func main() {
// Define a slice of Person structs with repeated ages
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 30},
{"Dave", 25},
}
// Define a custom comparison function to sort by Age
compareByAge := func(a, b Person) int {
return a.Age - b.Age
}
// Sort the slice by Age in ascending order with stable sorting
slices.SortStableFunc(people, compareByAge)
// Print the sorted slice
for _, person := range people {
fmt.Printf("%s: %d\n", person.Name, person.Age)
}
}
Output:
Bob: 25
Dave: 25
Alice: 30
Charlie: 30
Explanation:
- The
slices.SortStableFuncfunction sorts thepeopleslice by theAgefield while preserving the relative order of people with the same age.
Custom Stable Sorting for Complex Types
This example demonstrates how slices.SortStableFunc can be used to sort a slice of complex types based on multiple fields while maintaining stability.
Example
package main
import (
"fmt"
"slices"
)
type Product struct {
Name string
Price float64
Rating float64
}
func main() {
// Define a slice of Product structs with repeated ratings
products := []Product{
{"Laptop", 1000.0, 4.5},
{"Phone", 800.0, 4.7},
{"Tablet", 600.0, 4.5},
{"Monitor", 200.0, 4.7},
}
// Define a custom comparison function to sort by Rating, then by Price
compareByRatingAndPrice := func(a, b Product) int {
if a.Rating != b.Rating {
if a.Rating > b.Rating {
return 1
}
return -1
}
if a.Price > b.Price {
return 1
}
if a.Price < b.Price {
return -1
}
return 0
}
// Sort the slice by Rating, then by Price in ascending order with stable sorting
slices.SortStableFunc(products, compareByRatingAndPrice)
// Print the sorted slice
for _, product := range products {
fmt.Printf("%s: Price: %.2f, Rating: %.1f\n", product.Name, product.Price, product.Rating)
}
}
Output:
Tablet: Price: 600.00, Rating: 4.5
Laptop: Price: 1000.00, Rating: 4.5
Monitor: Price: 200.00, Rating: 4.7
Phone: Price: 800.00, Rating: 4.7
Explanation:
- The
slices.SortStableFuncfunction sorts theproductsslice byRatingand, within equal ratings, byPricewhile maintaining the original relative order of products with the same rating.
Real-World Use Case Example: Sorting Transactions by Amount and Date
A practical use case for slices.SortStableFunc is sorting a list of transactions by amount, while preserving the order of transactions that occurred on the same day.
Example: Sorting Transactions
package main
import (
"fmt"
"time"
"slices"
)
type Transaction struct {
Date time.Time
Amount float64
}
func main() {
// Define a slice of Transaction structs
transactions := []Transaction{
{time.Date(2024, 7, 10, 0, 0, 0, 0, time.UTC), 100.0},
{time.Date(2024, 7, 11, 0, 0, 0, 0, time.UTC), 200.0},
{time.Date(2024, 7, 10, 0, 0, 0, 0, time.UTC), 50.0},
{time.Date(2024, 7, 11, 0, 0, 0, 0, time.UTC), 150.0},
}
// Define a custom comparison function to sort by Amount
compareByAmount := func(a, b Transaction) int {
if a.Amount > b.Amount {
return 1
}
if a.Amount < b.Amount {
return -1
}
return 0
}
// Sort the slice by Amount in ascending order with stable sorting
slices.SortStableFunc(transactions, compareByAmount)
// Print the sorted transactions
for _, transaction := range transactions {
fmt.Printf("Date: %s, Amount: %.2f\n", transaction.Date.Format("2006-01-02"), transaction.Amount)
}
}
Output:
Date: 2024-07-10, Amount: 50.00
Date: 2024-07-10, Amount: 100.00
Date: 2024-07-11, Amount: 150.00
Date: 2024-07-11, Amount: 200.00
Explanation:
- The
slices.SortStableFuncfunction sorts thetransactionsslice byAmountwhile maintaining the original order of transactions that occurred on the same date.
Conclusion
The slices.SortStableFunc function in Go is used for stable sorting of slices based on custom comparison logic. It ensures that the relative order of elements that compare as equal is preserved, making it ideal for scenarios where the original order of equivalent elements is important. By using slices.SortStableFunc, you can efficiently sort your data in Go applications while maintaining the stability of the sort.