Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 按(任意)字段名对结构数组进行简单排序的最短方法是什么?_Sorting_Go - Fatal编程技术网

Sorting 按(任意)字段名对结构数组进行简单排序的最短方法是什么?

Sorting 按(任意)字段名对结构数组进行简单排序的最短方法是什么?,sorting,go,Sorting,Go,我只是有一个问题,我有一个数组的结构,例如 package main import "log" type Planet struct { Name string `json:"name"` Aphelion float64 `json:"aphelion"` // in million km Perihelion float64 `json:"perihelion"` // in million km Axis int64

我只是有一个问题,我有一个数组的结构,例如

package main

import "log"

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

func main() {
    var mars = new(Planet)
    mars.Name = "Mars"
    mars.Aphelion = 249.2
    mars.Perihelion = 206.7
    mars.Axis = 227939100
    mars.Radius = 3389.5

    var earth = new(Planet)
    earth.Name = "Earth"
    earth.Aphelion = 151.930
    earth.Perihelion = 147.095
    earth.Axis = 149598261
    earth.Radius = 6371.0

    var venus = new(Planet)
    venus.Name = "Venus"
    venus.Aphelion = 108.939
    venus.Perihelion = 107.477
    venus.Axis = 108208000
    venus.Radius = 6051.8

    planets := [...]Planet{*mars, *venus, *earth}
    log.Println(planets)
}
假设您想按
轴对其进行排序。你是怎么做到的


(注意:我已经看到了,而且它似乎可以工作,但是我必须添加大约20行,仅仅是为了通过一个非常简单的键进行简单的排序。我有一个python背景,它就像排序一样简单(planets,key=lambda n:n.Axis)
-Go中有类似的简单吗?

从Go 1.8开始,@AndreKR是更好的解决方案。


您可以实现一个集合类型,该集合类型实现了

允许您按轴或名称进行排序的两种类型:

package main

import "log"
import "sort"

// AxisSorter sorts planets by axis.
type AxisSorter []Planet

func (a AxisSorter) Len() int           { return len(a) }
func (a AxisSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a AxisSorter) Less(i, j int) bool { return a[i].Axis < a[j].Axis }

// NameSorter sorts planets by name.
type NameSorter []Planet

func (a NameSorter) Len() int           { return len(a) }
func (a NameSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a NameSorter) Less(i, j int) bool { return a[i].Name < a[j].Name }

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

func main() {
    var mars Planet
    mars.Name = "Mars"
    mars.Aphelion = 249.2
    mars.Perihelion = 206.7
    mars.Axis = 227939100
    mars.Radius = 3389.5

    var earth Planet
    earth.Name = "Earth"
    earth.Aphelion = 151.930
    earth.Perihelion = 147.095
    earth.Axis = 149598261
    earth.Radius = 6371.0

    var venus Planet
    venus.Name = "Venus"
    venus.Aphelion = 108.939
    venus.Perihelion = 107.477
    venus.Axis = 108208000
    venus.Radius = 6051.8

    planets := []Planet{mars, venus, earth}
    log.Println("unsorted:", planets)

    sort.Sort(AxisSorter(planets))
    log.Println("by axis:", planets)

    sort.Sort(NameSorter(planets))
    log.Println("by name:", planets)
}
主程序包
导入“日志”
导入“排序”
//AxisSorter按轴对行星进行排序。
类型AxisSorter[]行星
func(AxisSorter)Len()int{return Len(a)}
func(a轴排序器)交换(i,j int){a[i],a[j]=a[j],a[i]}
func(a AxisSorter)Less(i,j int)bool{返回a[i]。Axis
更新:此答案与较旧版本的
go
有关。有关Go 1.8及更新版本,请参阅


如果您想要比标准库
sort
软件包更简洁的东西,可以使用第三方软件包。它使用一些技巧来生成排序切片所需的
Len
Swap
方法,因此您只需要提供
Less
方法

使用此软件包,您可以通过以下方式执行排序:

slice.Sort(planets[:], func(i, j int) bool {
    return planets[i].Axis < planets[j].Axis
})
slice.Sort(行星[:],函数(i,j int)bool{
返回行星[i]。轴<行星[j]。轴
})

planets[:]
部件是生成覆盖阵列的切片所必需的。如果将
Planet
制作为切片而不是数组,则可以跳过该部分。

您可以在包含集合的类型上实现排序接口,而不是在
[]Planet
上实现排序接口。您必须为每个属性提供比较闭包的实现

我觉得这种方法比为结构的每个属性实现排序类型要好

这个答案几乎是从字面上扯下来的,所以我不能为它赢得太多的信任

package main

import (
    "log"
    "sort"
)

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

type By func(p1, p2 *Planet) bool

func (by By) Sort(planets []Planet) {
    ps := &planetSorter{
        planets: planets,
        by:      by, 
    }
    sort.Sort(ps)
}

type planetSorter struct {
    planets []Planet
    by      func(p1, p2 *Planet) bool 
}

func (s *planetSorter) Len() int {
    return len(s.planets)
}

func (s *planetSorter) Swap(i, j int) {
    s.planets[i], s.planets[j] = s.planets[j], s.planets[i]
}

func (s *planetSorter) Less(i, j int) bool {
    return s.by(&s.planets[i], &s.planets[j])
}
怎么称呼它

func main() {
    /* Same code as in the question */

    planets := []Planet{*mars, *venus, *earth}

    By(func(p1, p2 *Planet) bool {
        return p1.Name < p2.Name
    }).Sort(planets)

    log.Println(planets)

    By(func(p1, p2 *Planet) bool {
        return p1.Axis < p2.Axis
    }).Sort(planets)

    log.Println(planets)
}
func main(){
/*与问题中的代码相同*/
行星:=[]行星{*火星,*金星,*地球}
By(func(p1,p2*行星)bool{
返回p1.Name

这里是另一种减少锅炉板厚度的方法。免责声明,它使用反射和丢失类型安全

所有的魔法都发生在
Prop
功能中。它采用struct属性进行排序,并按照您想要排序的顺序(升序、降序)进行排序,然后返回一个将执行比较的函数

package main

import (
    "log"
    "reflect"
    "sort"
)

func test(planets []Planet) {
    log.Println("Sort Name")
    By(Prop("Name", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Aphelion")
    By(Prop("Aphelion", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Perihelion")
    By(Prop("Perihelion", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Axis")
    By(Prop("Axis", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Radius")
    By(Prop("Radius", true)).Sort(planets)
    log.Println(planets)
}

func Prop(field string, asc bool) func(p1, p2 *Planet) bool {
    return func(p1, p2 *Planet) bool {

        v1 := reflect.Indirect(reflect.ValueOf(p1)).FieldByName(field)
        v2 := reflect.Indirect(reflect.ValueOf(p2)).FieldByName(field)

        ret := false

        switch v1.Kind() {
        case reflect.Int64:
            ret = int64(v1.Int()) < int64(v2.Int())
        case reflect.Float64:
            ret = float64(v1.Float()) < float64(v2.Float())
        case reflect.String:
            ret = string(v1.String()) < string(v2.String())
        }

        if asc {
            return ret
        }
        return !ret
    }
}

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

type By func(p1, p2 *Planet) bool

func (by By) Sort(planets []Planet) {
    ps := &planetSorter{
        planets: planets,
        by:      by, // The Sort method's receiver is the function (closure) that defines the sort order.
    }
    sort.Sort(ps)
}

type planetSorter struct {
    planets []Planet
    by      func(p1, p2 *Planet) bool // Closure used in the Less method.
}

// Len is part of sort.Interface.
func (s *planetSorter) Len() int { return len(s.planets) }

// Swap is part of sort.Interface.
func (s *planetSorter) Swap(i, j int) {
    s.planets[i], s.planets[j] = s.planets[j], s.planets[i]
}

// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
func (s *planetSorter) Less(i, j int) bool {
    return s.by(&s.planets[i], &s.planets[j])
}

func main() {
    test(dataSet())
}

func dataSet() []Planet {

    var mars = new(Planet)
    mars.Name = "Mars"
    mars.Aphelion = 249.2
    mars.Perihelion = 206.7
    mars.Axis = 227939100
    mars.Radius = 3389.5

    var earth = new(Planet)
    earth.Name = "Earth"
    earth.Aphelion = 151.930
    earth.Perihelion = 147.095
    earth.Axis = 149598261
    earth.Radius = 6371.0

    var venus = new(Planet)
    venus.Name = "Venus"
    venus.Aphelion = 108.939
    venus.Perihelion = 107.477
    venus.Axis = 108208000
    venus.Radius = 6051.8

    return []Planet{*mars, *venus, *earth}
}
主程序包
进口(
“日志”
“反映”
“排序”
)
func测试(行星[]行星){
log.Println(“排序名称”)
按(Prop(“Name”,true)).Sort(行星)
log.Println(行星)
log.Println(“排序Aphelion”)
通过(道具(“幻觉”,真实))排序(行星)
log.Println(行星)
log.Println(“排序近日点”)
通过(道具(“近日点”,真))排序(行星)
log.Println(行星)
log.Println(“排序轴”)
按(Prop(“Axis”,true))排序(行星)
log.Println(行星)
log.Println(“排序半径”)
按(道具(“半径”,真))排序(行星)
log.Println(行星)
}
func Prop(字段字符串,asc布尔)func(p1,p2*行星)布尔{
返回函数(p1,p2*行星)布尔{
v1:=reflect.Indirect(reflect.ValueOf(p1)).FieldByName(字段)
v2:=reflect.Indirect(reflect.ValueOf(p2)).FieldByName(字段)
ret:=假
开关v1.Kind(){
case reflect.Int64:
ret=int64(v1.Int())sort.Slice(planets, func(i, j int) bool {
  return planets[i].Axis < planets[j].Axis
})
sort.Slice(planets[:], func(i, j int) bool {
  return planets[i].Axis < planets[j].Axis
})
package main

import (
    "fmt"
)

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

func main() {
    var mars Planet
    mars.Name = "Mars"
    mars.Aphelion = 249.2
    mars.Perihelion = 206.7
    mars.Axis = 227939100
    mars.Radius = 3389.5

    var earth Planet
    earth.Name = "Earth"
    earth.Aphelion = 151.930
    earth.Perihelion = 147.095
    earth.Axis = 149598261
    earth.Radius = 6371.0

    var venus Planet
    venus.Name = "Venus"
    venus.Aphelion = 108.939
    venus.Perihelion = 107.477
    venus.Axis = 108208000
    venus.Radius = 6051.8

    planets := []Planet{mars, venus, earth}
    fmt.Println(quickSort(&planets,0,len(planets)-1))

}

func quickSort(arr *[]Planet, start, end int)[]Planet{
    if start < end{
        partitionIndex := partition(*arr,start,end)
        quickSort(arr,start,partitionIndex-1)
        quickSort(arr,partitionIndex+1, end)
    }
    return *arr
}

func partition(arr []Planet, start, end int) int{
    pivot := arr[end].Name
    pIndex := start
    for i:= start; i<end; i++{
        if arr[i].Name <= pivot{
            //  swap
            arr[i],arr[pIndex] = arr[pIndex],arr[i]
            pIndex++
        }
    }
    arr[pIndex],arr[end] = arr[end],arr[pIndex]
    return pIndex
}