我需要对来自第 3 方包的类型的切片进行排序。根据某些条件,顺序必须是升序或降序。
我想出的解决方案是:
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))
}
有没有更好的方法来做到这一点。这个任务需要 13 行代码,而且大部分都是重复的,看起来有点太多了。
从 Go 1.8 开始,有一种更简单的方法来对切片进行排序,不需要定义新类型。您只需将匿名函数传递给
sort.Slice
函数即可。
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)
}
这将按升序排序,如果你想要相反的顺序,只需在匿名函数中写
a[i] > a[j]
即可。
我下面的回答基于这样的假设:您从第三方包收到的切片是基本的 Go 类型。
要对基本类型的切片进行排序,请使用排序包实用程序。这是一个对字符串切片和整数切片进行排序的示例。
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)
}
上面的输出是:
[london mumbai seattle tokyo]
[-34 2 3 4 5 6 293]
前往这里去游乐场亲自尝试一下。
一些注意事项:
对基本 Go 类型进行排序不需要实现 Len() 等属于 sort.Interface 的函数。您只需要对复合类型采取该路线。
只需使用适当的接口方法提供者包装基本类型的类型,例如StringSlice、IntSlice 或 Float64Slice,然后排序。
切片已就地排序,因此不会返回已排序切片的副本。
接受的答案很好,但我不同意他们关于降序的建议:
a[i] > a[j]
使用
sort.Slice
,所提供的函数应该代表一个
“小于”的实现:
给定提供的func Slice(x interface{}, less func(i, j int) bool)
Slice
函数,对切片x
进行排序。如果less
不是切片,它会出现恐慌。x
因此,编写“大于”函数并不符合给定的描述。更好的办法是反转索引:
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]
}
两者都应该返回相同的结果,但我认为其中一个更惯用。
也许你可以使用
sort.Sort
方法对切片进行排序。 :)
func TestSorted(t *testing.T) {
nums := []int{4, 3, 2, 3, 5, 2, 1}
// descending
sort.Sort(sort.Reverse(sort.IntSlice(nums)))
fmt.Println(nums) // [5 4 3 3 2 2 1]
// ascending
sort.Sort(sort.IntSlice(nums))
fmt.Println(nums) // [1 2 2 3 3 4 5]
}
您可以从 golang 标准库导入“sort”包。那么您可以使用“Slice”或“SliceStable”函数对切片进行排序。建议使用第二个,如下所示:
sort.SliceStable(yourSlice , anonnymousFunction)
示例: 包主
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)
}
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)
Go Playgound 的链接 https://play.golang.org/p/Q8KY_JE__kx
package main
import (
"fmt"
"sort"
)
func main() {
// unsorted string and integer slices
strData := []string{"Go", "Bravo", "Gopher", "Alpha", "Grin", "Delta"}
intData := []int{5, 2, 6, 3, 1, 4}
// sort in-place in ascending order
sort.Ints(intData)
sort.Strings(strData)
// print
fmt.Println(intData)
fmt.Println(strData)
}
输出:
[Alpha Bravo Delta Go Gopher Grin]
[1 2 3 4 5 6]
package main
import (
"fmt"
"sort"
)
func main() {
// unsorted int and string slices
strData := []string{"Go", "Bravo", "Gopher", "Alpha", "Grin", "Delta"}
intData := []int{5, 2, 6, 3, 1, 4}
// sort in-place in descending order
sort.Sort(sort.Reverse(sort.IntSlice(intData)))
sort.Sort(sort.Reverse(sort.StringSlice(strData)))
// print
fmt.Println(intData)
fmt.Println(strData)
}
输出:
[6 5 4 3 2 1]
[Grin Gopher Go Delta Bravo Alpha]
在 Go 1.21 中,添加了一个新包 slices。它包含几个用于处理切片的通用函数。
slices.Sort()
[ref] 可以对任意 有序类型 的切片进行排序,例如 int
、float64
、string
。比sort.Sort()
还要快。
s := []int{5, 2, 6, 3, 1, 4}
// sorts in asc order
slices.Sort(s)
// reverse the slice for desc order
slices.Reverse(s)
如果切片的元素没有有序类型,那么您可以使用
slices.SortFunc()
。以下示例取自官方文档。
package main
import (
"cmp"
"fmt"
"slices"
)
type Person struct {
Name string
Age int
}
func CmpPerson(a, b Person) int {
if a.Name == b.Name {
return cmp.Compare(a.Age, b.Age)
}
return cmp.Compare(a.Name, b.Name)
}
func main() {
people := []Person{
{"Gopher", 13},
{"Alice", 55},
{"Bob", 24},
{"Alice", 20},
}
slices.SortFunc(people, CmpPerson)
// Output: [{Alice 20} {Alice 55} {Bob 24} {Gopher 13}]
fmt.Println(people)
}
与
sort.Slice()
不同,比较器函数 CmpPerson()
将切片的元素而不是其索引作为参数。
所以现在,您可以使用与
slices.Reverse()
相同的比较器,也可以定义另一个比较器进行降序排列。
请注意,
slices.SortFunc()
不稳定。为了稳定排序,您可以使用 slices.SortStableFunc()
,它与
slices.SortFunc()
具有相同的签名。
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
}