golang 对切片升序或降序排序

问题描述 投票:0回答:10

我需要对来自第 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 行代码,而且大部分都是重复的,看起来有点太多了。

sorting go
10个回答
176
投票

从 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]
即可。


28
投票

您正在寻找

sort.Reverse
。那会让你说:

sort.Sort(sort.Reverse(fooAscending(s)))

22
投票

我下面的回答基于这样的假设:您从第三方包收到的切片是基本的 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]

前往这里去游乐场亲自尝试一下。

一些注意事项:

  1. 对基本 Go 类型进行排序不需要实现 Len() 等属于 sort.Interface 的函数。您只需要对复合类型采取该路线。

  2. 只需使用适当的接口方法提供者包装基本类型的类型,例如StringSliceIntSliceFloat64Slice,然后排序。

  3. 切片已就地排序,因此不会返回已排序切片的副本。


11
投票

接受的答案很好,但我不同意他们关于降序的建议:

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]
}

两者都应该返回相同的结果,但我认为其中一个更惯用。

https://golang.org/pkg/sort#Slice


6
投票

也许你可以使用

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]
}

4
投票

您可以从 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)
}

2
投票
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


0
投票

升序排列:

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]

0
投票

在 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()
 具有相同的签名。


-2
投票
如果由于任何原因你不能或不想使用 sort 包,下面将实现冒泡排序类型的排序(它接受 int64 切片并返回 int64 切片):

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 }
    
© www.soinside.com 2019 - 2024. All rights reserved.