在go lang中按不同的维度对点(结构)进行排序

时间:2013-11-03 23:00:12

标签: sorting struct go

我有一个Points类型的多维点列表。

我已经实现了sort.Sort界面,现在可以按y value排序。

e.g。

type Points []*Point

func (points Points) Len() int {
    return len(points)
}
func (points Points) Less(i, j int) bool {
    return points[i].y < points[j].y
}
func (points Points) Swap(i, j int) {
    points[i], points[j] = points[j], points[i]
}

type Point struct {
    x int
    y int
    country_id int
}

现在我想按x value而不是y value对点进行排序。

我的想法是使用带有全局标志的if语句(可以在排序之前打开或关闭):

func (points Points) Less(i, j int) bool {
    if SORT_BY_X {
        return points[i].x < points[j].x
    }
    return points[i].y < points[j].y
}

有更好的方法吗?我应该多次实施Less吗?如果我按列排序数据表怎么办?

2 个答案:

答案 0 :(得分:7)

啊,这很有趣:sort.Sort()期望类型定义排序和一些数组操作。你可以拥有“X-sortable point list”和“Y-sortable point list”类型,但是让它们共享数组ops与其他语言的工作方式不同,因为Go不使用继承。

我想到的第一种方法是创建XSortablePointsYSortablePoints类型,每个类型都独立实现sort.Interface,并将您的Points实例转换为您需要的XSortablePoints实例。时刻 - 见这里:http://play.golang.org/p/9V3WlKjOwX

然后nemo有一个更好的方法:类型嵌入允许YSortablePointsSORT_BY_X共享数组操作的函数。此外,nemo不会将可排序类型保存在变量中,这是有意义的,因为它们仅存在于此一个排序调用中。这是经过调整的示例代码:http://play.golang.org/p/wNm-ilM18n

请注意,这两种方法都不会在您投射时实际复制您的点数据,只是切片标题。您可以通过查看第一个示例打印出的指针地址来查看。

你可以获得更多的动力:有一个Points.Sort在http://play.golang.org/p/4PmJVi2_7D采取任意比较功能。我认为只要定义更多类型的蛮力方法就可以,只要您只有两个或三个排序,但情况会有所不同。请注意,对于比这里的点大得多的类型,您可能希望将比较器定义为采用指针而不是值,以避免复制。

re:false:我通常会避免在程序运行时更新的全局模式设置变量,因为有很多方法可以让你回过头来咬你。例如,也许你有一天会有两个并行的goroutine,然后当它们同时访问全局时会出现问题。或者,当SORT_BY_X的初始值为true时,某些代码可能会起作用,然后有一天会失败,因为在另一个任务运行后它被留下{{1}}。如果您确实发现自己需要一个模式变量,请确定是否可以将其作为函数参数或将其附加到对象,而不是它是全局变量。

最后,可能有一个软件包已经提供了您想要的一些更高级别的功能。例如,有一些与此处列出的地理数据相关的包:https://code.google.com/p/go-wiki/wiki/Projects#GIS

答案 1 :(得分:5)

除了user2714852的答案,你可以使用与already used相同的技巧 逆转sort包中的排序:遮蔽Less()定义。

虽然这与已经提出的相似,但实现目标的方式却是如此 有点不同(example on play)。你定义你的要点:

type Points []Point

func (points Points) Swap(i, j int) {
    points[i], points[j] = points[j], points[i]
}

func (points Points) Len() int {
    return len(points)
}

对于每种排序方法,您都可以实现嵌入Points类型的自己的类型:

type XPoints struct {
    Points
}

func (points XPoints) Less(i,j int) bool {
    return points.Points[i].x < points.Points[j].x
}

type YPoints struct {
    Points
}

func (points YPoints) Less(i, j int) bool {
    return points.Points[i].y < points.Points[j].y
}

现在您可以使用不同的排序方法:

pts := Points{{1, 2, 3}, {2, 1, 3}}

sort.Sort(XPoints{pts})
fmt.Println("X-sorted points:", pts)

sort.Sort(YPoints{pts})
fmt.Println("Y-sorted points:", pts)