golang sort slice ascending or descending
SortingGoSorting Problem Overview
I need to sort a slice of a type that is coming from a 3rdparty package. Based on some condition the order must be ascending or descending.
The solution I come up with is:
type fooAscending []foo
func (v fooAscending) Len() int { return len(v) }
func (v fooAscending) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v fooAscending) Less(i, j int) bool { return v[i].Amount < v[j].Amount }
type fooDescending []foo
func (v fooDescending) Len() int { return len(v) }
func (v fooDescending) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v fooDescending) Less(i, j int) bool { return v[i].Amount > v[j].Amount }
if someCondition {
sort.Sort(fooAscending(array))
} else {
sort.Sort(fooDescending(array))
}
Is there a better way to do this. 13 lines of code for this task and most of it is duplicated, seems a bit too much.
Sorting Solutions
Solution 1 - Sorting
As of Go 1.8, there is an easier way to sort a slice that does not require you to define new types. You simply pass an anonymous function to the sort.Slice
function.
a := []int{5, 3, 4, 7, 8, 9}
sort.Slice(a, func(i, j int) bool {
return a[i] < a[j]
})
for _, v := range a {
fmt.Println(v)
}
This will sort in ascending order, if you want the opposite, simply write a[i] > a[j]
in the anonymous function.
Solution 2 - Sorting
You're looking for sort.Reverse
. That will let you say:
sort.Sort(sort.Reverse(fooAscending(s)))
Solution 3 - Sorting
My answer below is based on the assumption that the slice that you are receiving from a third party package is of a basic Go type.
To sort slices of basic types, use the sort package utilities. Here is an example that sorts a slice of string and a slice of int.
package main
import (
"fmt"
"sort"
)
func main() {
sl := []string{"mumbai", "london", "tokyo", "seattle"}
sort.Sort(sort.StringSlice(sl))
fmt.Println(sl)
intSlice := []int{3,5,6,4,2,293,-34}
sort.Sort(sort.IntSlice(intSlice))
fmt.Println(intSlice)
}
The output of the above is:
[london mumbai seattle tokyo]
[-34 2 3 4 5 6 293]
Go to Go Playground here to try it out yourself.
A few things of note:
-
Sorting basic Go types does not require implementing functions such as Len() that belong to sort.Interface. You need to take that route only for composite types.
-
Just wrap the type of a basic type using an appropriate Interface method provider, e.g. StringSlice, IntSlice, or Float64Slice, and sort.
-
The slice is sorted in-place, and hence does not return a copy of the sorted slice.
Solution 4 - Sorting
The accepted answer is good, but I disagree with their suggestion on descending:
a[i] > a[j]
With sort.Slice
, the provided function is suppposed to represent an
implementation of "less than":
> func Slice(x interface{}, less func(i, j int) bool)
>
> Slice
sorts the slice x
given the provided less
function. It panics if
> x
is not a slice.
So writing a "greater than" function, isnt really true to the given description. Better would be to reverse the indexes:
package main
import (
"fmt"
"sort"
)
func main() {
a := []int{5, 3, 4, 7, 8, 9}
sort.Slice(a, func(i, j int) bool {
return a[j] < a[i]
})
fmt.Println(a) // [9 8 7 5 4 3]
}
both should return the same result, but I think one is more idiomatic.
Solution 5 - Sorting
you can import the "sort" package from standard library of golang . then you can use either "Slice" or "SliceStable" function to sort your slice. it is recommended to use the second one like this :
sort.SliceStable(yourSlice , anonnymousFunction)
example : package main
import (
"fmt"
"sort"
)
func main() {
a := []int{4,5,9,6,8,3,5,7,99,58,1}
sort.SliceStable(a, func(i,j int )bool{
//i,j are represented for two value of the slice .
return a[i] < a[j]
})
fmt.Println(a)
}
Solution 6 - Sorting
`var names = []string{"b", "a", "e", "c", "d"}
sort.Strings(names)
fmt.Println("Sorted in alphabetical order", names)
sort.Sort(sort.Reverse(sort.StringSlice(names)))
fmt.Println("Sorted in reverse order", names)`
link for The Go Playgound https://play.golang.org/p/Q8KY_JE__kx
Solution 7 - Sorting
if for any reasons you can't or don't want to use the sort package, the following will implement a bubble sort type of sorting (it accepts an int64 slice and returns an int64 slice):
func sortSlice ( S []int64 ) []int64 {
// sort using bubblesort, comparing each pairs of numbers and ensuring that left is lower than right
for i := len(S); i > 0 ; i-- {
for j := 1; j < i; j++ {
if S[j-1] > S[j] {
// swap
intermediate := S[j]
S[j] = S[j-1]
S[j-1] = intermediate
}
}
}
return S
}