在Go语言中对自定义结构数组进行排序。

huangapple go评论69阅读模式
英文:

Sort a custom struct array in GoLang

问题

如何使用GoLang对自定义结构的数组进行排序。

我的代码是:

package main

import "fmt"

type TicketDistribution struct {
	Label        string
	TicketVolume int64
}

type TicketDistributionResponse struct {
	LevelDistribution []*TicketDistribution
}

func main() {
	var response TicketDistributionResponse

	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "John", TicketVolume: 3})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Bill", TicketVolume: 7})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Sam", TicketVolume: 4})

	for _, val := range response.LevelDistribution {
		fmt.Println(*val)
	}

}

这将打印输出:

{John 3}
{Bill 7}
{Sam 4}

我想按照TicketVolume值的降序对response对象进行排序。

排序后,response对象应该如下所示:

{Bill 7}
{Sam 4}
{John 3}
英文:

How do I sort a custom array of struct using GoLang.

My Code is :

package main

import "fmt"

type TicketDistribution struct {
	Label        string
	TicketVolume int64
}

type TicketDistributionResponse struct {
	LevelDistribution []*TicketDistribution
}

func main() {
	var response TicketDistributionResponse

	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "John", TicketVolume: 3})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Bill", TicketVolume: 7})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Sam", TicketVolume: 4})

	for _, val := range response.LevelDistribution {
		fmt.Println(*val)
	}

}

This prints the output as


{John 3}
{Bill 7}
{Sam 4}

I want to sort the response object by TicketVolume value in descending order.

After the sort the response object should look like :

{Bill 7}
{Sam 4}
{John 3}

答案1

得分: 1

你可以使用sort.Slice来实现。它接受你的切片和一个排序函数。
排序函数本身接受两个索引,并在左侧项小于右侧项时返回true。

通过这种方式,你可以按照自定义的条件进行排序。

package main

import (
	"fmt"
	"sort"
)

type TicketDistribution struct {
	Label        string
	TicketVolume int64
}

type TicketDistributionResponse struct {
	LevelDistribution []*TicketDistribution
}

func main() {
	var response TicketDistributionResponse

	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "John", TicketVolume: 3})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Bill", TicketVolume: 7})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Sam", TicketVolume: 4})

	sort.Slice(response.LevelDistribution, func(i, j int) bool {
		a := response.LevelDistribution[i]
		b := response.LevelDistribution[j]
		return a.TicketVolume > b.TicketVolume
	})

	for _, val := range response.LevelDistribution {
		fmt.Println(*val)
	}
}

在比较函数中使用>可以按降序对切片进行排序,如果要按升序排序,可以使用<

英文:

You can use sort.Slice for that. It takes your slice and a sort function.
The sort function itself takes two indices and returns true if the left item is smaller than the right one.

This way you can sort by your own custom criteria.

package main

import (
	"fmt"
	"sort"
)

type TicketDistribution struct {
	Label        string
	TicketVolume int64
}

type TicketDistributionResponse struct {
	LevelDistribution []*TicketDistribution
}

func main() {
	var response TicketDistributionResponse

	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "John", TicketVolume: 3})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Bill", TicketVolume: 7})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Sam", TicketVolume: 4})

	sort.Slice(response.LevelDistribution, func(i, j int) bool {
		a := response.LevelDistribution[i]
		b := response.LevelDistribution[j]
		return a.TicketVolume > b.TicketVolume
	})

	for _, val := range response.LevelDistribution {
		fmt.Println(*val)
	}
}

The use of > in the comparison function sorts the slice descendingly, for ascending order you would use <.

答案2

得分: 0

你可以使用slice.Interface。你可以通过定义以下三个方法来为你的结构体实现sort.Interface接口。

type Interface interface {
	// Len返回集合中的元素数量。
	Len() int

	// Less报告索引为i的元素是否必须在索引为j的元素之前排序。
	Less(i, j int) bool

	// Swap交换索引为i和j的元素。
	Swap(i, j int)
}

性能:对切片进行排序 vs 对切片类型进行排序(使用Sort实现)

通用的sort.Slice()和sort.SliceStable()函数适用于任何切片。你必须将切片值作为interface{}值传递,并且实现必须使用反射(reflect包)来访问其元素和长度,并执行元素的交换。

相比之下,当你自己实现sort.Interface类型时,在你的实现中,你可以访问切片的静态类型,并且可以提供sort.Interface的实现而不使用反射,这将使其更快。

以下是更新后的代码:

package main

import (
	"fmt"
	"sort"
)

type TicketDistribution struct {
	Label        string
	TicketVolume int64
}

type LevelDistribution []*TicketDistribution

func (ld LevelDistribution) Len() int {
	return len(ld)
}
func (ld LevelDistribution) Swap(i, j int) {
	ld[i], ld[j] = ld[j], ld[i]
}
func (ld LevelDistribution) Less(i, j int) bool {
	return ld[i].TicketVolume > ld[j].TicketVolume
}

type TicketDistributionResponse struct {
	LevelDistribution LevelDistribution
}

func main() {
	var response TicketDistributionResponse

	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "John", TicketVolume: 3})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Bill", TicketVolume: 7})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Sam", TicketVolume: 4})

	ld := LevelDistribution(response.LevelDistribution)
	sort.Sort(ld)

	for _, val := range response.LevelDistribution {
		fmt.Println(*val)
	}
}

以下是基准测试的输出结果,接口/结构体方法在这里也更好:

> go test -bench=. -benchmem

goos: linux
goarch: amd64
pkg: solutions/golang/sort
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
BenchmarkWithInterface-8    5368116    191.0 ns/op    152 B/op    7 allocs/op
BenchmarkWithSlice-8        5085151    234.9 ns/op    184 B/op    8 allocs/op
PASS
英文:

You can use slice.Interface also. You can implement the sort.Interface interface for your struct by defining these three methods.

type Interface interface {
	// Len is the number of elements in the collection.
	Len() int

	// Less reports whether the element with index i
	// must sort before the element with index j.
	Less(i, j int) bool

	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}

Performance: Sorting Slice vs Sorting Type (of Slice) with Sort implementation
> The general sort.Slice() and sort.SliceStable() functions work on any slices. You have to pass your slice value as an interface{} value, and the implementation has to use reflection (the reflect package) to access its elements and length, and to perform the swaps of elements.

> In contrast, when you implement the sort.Interface type yourself, in your implementation you have access to the static type of your slice, and you can provide the implementation of the sort.Interface without relfection, this is what will make it faster.

Here is the updated code

package main

import (
	"fmt"
	"sort"
)

type TicketDistribution struct {
	Label        string
	TicketVolume int64
}

type LevelDistribution []*TicketDistribution

func (ld LevelDistribution) Len() int {
	return len(ld)
}
func (ld LevelDistribution) Swap(i, j int) {
	ld[i], ld[j] = ld[j], ld[i]
}
func (ld LevelDistribution) Less(i, j int) bool {
	return ld[i].TicketVolume > ld[j].TicketVolume
}

type TicketDistributionResponse struct {
	LevelDistribution LevelDistribution
}

func main() {
	var response TicketDistributionResponse

	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "John", TicketVolume: 3})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Bill", TicketVolume: 7})
	response.LevelDistribution = append(response.LevelDistribution, &TicketDistribution{Label: "Sam", TicketVolume: 4})

	ld := LevelDistribution(response.LevelDistribution)
	sort.Sort(ld)

	for _, val := range response.LevelDistribution {
		fmt.Println(*val)
	}
}

Here is the benchmark run output looks like the interface/struct method is better there too

> go test -bench=. -benchmem

goos: linux
goarch: amd64
pkg: solutions/golang/sort
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
BenchmarkWithInterface-8   	 5368116	       191.0 ns/op	     152 B/op	       7 allocs/op
BenchmarkWithSlice-8       	 5085151	       234.9 ns/op	     184 B/op	       8 allocs/op
PASS

huangapple
  • 本文由 发表于 2023年7月15日 15:43:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76692739.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定