mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-13 17:22:27 +08:00
feat: add SortBy function for slice
This commit is contained in:
@@ -725,6 +725,12 @@ func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SortBy sorts the slice in ascending order as determined by the less function.
|
||||||
|
// This sort is not guaranteed to be stable
|
||||||
|
func SortBy[T any](slice []T, less func(a, b T) bool) {
|
||||||
|
quickSortBy(slice, 0, len(slice)-1, less)
|
||||||
|
}
|
||||||
|
|
||||||
// SortByField return sorted slice by field
|
// SortByField return sorted slice by field
|
||||||
// slice element should be struct, field type should be int, uint, string, or bool
|
// slice element should be struct, field type should be int, uint, string, or bool
|
||||||
// default sortType is ascending (asc), if descending order, set sortType to desc
|
// default sortType is ascending (asc), if descending order, set sortType to desc
|
||||||
|
|||||||
@@ -29,14 +29,14 @@ func sliceElemType(reflectType reflect.Type) reflect.Type {
|
|||||||
|
|
||||||
func quickSort[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) {
|
func quickSort[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) {
|
||||||
if lowIndex < highIndex {
|
if lowIndex < highIndex {
|
||||||
p := partition(slice, lowIndex, highIndex, order)
|
p := partitionOrderedSlice(slice, lowIndex, highIndex, order)
|
||||||
quickSort(slice, lowIndex, p-1, order)
|
quickSort(slice, lowIndex, p-1, order)
|
||||||
quickSort(slice, p+1, highIndex, order)
|
quickSort(slice, p+1, highIndex, order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// partition split slice into two parts for quick sort
|
// partitionOrderedSlice split ordered slice into two parts for quick sort
|
||||||
func partition[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) int {
|
func partitionOrderedSlice[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int, order string) int {
|
||||||
p := slice[highIndex]
|
p := slice[highIndex]
|
||||||
i := lowIndex
|
i := lowIndex
|
||||||
|
|
||||||
@@ -59,6 +59,32 @@ func partition[T lancetconstraints.Ordered](slice []T, lowIndex, highIndex int,
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quickSortBy[T any](slice []T, lowIndex, highIndex int, less func(a, b T) bool) {
|
||||||
|
if lowIndex < highIndex {
|
||||||
|
p := partitionAnySlice(slice, lowIndex, highIndex, less)
|
||||||
|
quickSortBy(slice, lowIndex, p-1, less)
|
||||||
|
quickSortBy(slice, p+1, highIndex, less)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// partitionAnySlice split any slice into two parts for quick sort
|
||||||
|
func partitionAnySlice[T any](slice []T, lowIndex, highIndex int, less func(a, b T) bool) int {
|
||||||
|
p := slice[highIndex]
|
||||||
|
i := lowIndex
|
||||||
|
|
||||||
|
for j := lowIndex; j < highIndex; j++ {
|
||||||
|
|
||||||
|
if less(slice[j], p) {
|
||||||
|
swap(slice, i, j)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(slice, i, highIndex)
|
||||||
|
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
// swap two slice value at index i and j
|
// swap two slice value at index i and j
|
||||||
func swap[T any](slice []T, i, j int) {
|
func swap[T any](slice []T, i, j int) {
|
||||||
slice[i], slice[j] = slice[j], slice[i]
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
|||||||
@@ -558,6 +558,36 @@ func TestSort(t *testing.T) {
|
|||||||
assert.Equal([]string{"e", "d", "c", "b", "a"}, strings)
|
assert.Equal([]string{"e", "d", "c", "b", "a"}, strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSortBy(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSortBy")
|
||||||
|
|
||||||
|
numbers := []int{1, 4, 3, 2, 5}
|
||||||
|
|
||||||
|
SortBy(numbers, func(a, b int) bool {
|
||||||
|
return a < b
|
||||||
|
})
|
||||||
|
assert.Equal([]int{1, 2, 3, 4, 5}, numbers)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string
|
||||||
|
Age uint
|
||||||
|
}
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{Name: "a", Age: 21},
|
||||||
|
{Name: "b", Age: 15},
|
||||||
|
{Name: "c", Age: 100}}
|
||||||
|
|
||||||
|
SortBy(users, func(a, b User) bool {
|
||||||
|
return a.Age < b.Age
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Logf("sort users by age: %v", users)
|
||||||
|
|
||||||
|
// output
|
||||||
|
// [{b 15} {a 21} {c 100}]
|
||||||
|
}
|
||||||
|
|
||||||
func TestSortByFielDesc(t *testing.T) {
|
func TestSortByFielDesc(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestSortByFielDesc")
|
assert := internal.NewAssert(t, "TestSortByFielDesc")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user