97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
// Copyright 2013 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package sort_test
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
// A couple of type definitions to make the units clear.
|
|
type earthMass float64
|
|
type au float64
|
|
|
|
// A Planet defines the properties of a solar system object.
|
|
type Planet struct {
|
|
name string
|
|
mass earthMass
|
|
distance au
|
|
}
|
|
|
|
// By is the type of a "less" function that defines the ordering of its Planet arguments.
|
|
type By func(p1, p2 *Planet) bool
|
|
|
|
// Sort is a method on the function type, By, that sorts the argument slice according to the function.
|
|
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)
|
|
}
|
|
|
|
// planetSorter joins a By function and a slice of Planets to be sorted.
|
|
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])
|
|
}
|
|
|
|
var planets = []Planet{
|
|
{"Mercury", 0.055, 0.4},
|
|
{"Venus", 0.815, 0.7},
|
|
{"Earth", 1.0, 1.0},
|
|
{"Mars", 0.107, 1.5},
|
|
}
|
|
|
|
// ExampleSortKeys demonstrates a technique for sorting a struct type using programmable sort criteria.
|
|
func Example_sortKeys() {
|
|
// Closures that order the Planet structure.
|
|
name := func(p1, p2 *Planet) bool {
|
|
return p1.name < p2.name
|
|
}
|
|
mass := func(p1, p2 *Planet) bool {
|
|
return p1.mass < p2.mass
|
|
}
|
|
distance := func(p1, p2 *Planet) bool {
|
|
return p1.distance < p2.distance
|
|
}
|
|
decreasingDistance := func(p1, p2 *Planet) bool {
|
|
return !distance(p1, p2)
|
|
}
|
|
|
|
// Sort the planets by the various criteria.
|
|
By(name).Sort(planets)
|
|
fmt.Println("By name:", planets)
|
|
|
|
By(mass).Sort(planets)
|
|
fmt.Println("By mass:", planets)
|
|
|
|
By(distance).Sort(planets)
|
|
fmt.Println("By distance:", planets)
|
|
|
|
By(decreasingDistance).Sort(planets)
|
|
fmt.Println("By decreasing distance:", planets)
|
|
|
|
// Output: By name: [{Earth 1 1} {Mars 0.107 1.5} {Mercury 0.055 0.4} {Venus 0.815 0.7}]
|
|
// By mass: [{Mercury 0.055 0.4} {Mars 0.107 1.5} {Venus 0.815 0.7} {Earth 1 1}]
|
|
// By distance: [{Mercury 0.055 0.4} {Venus 0.815 0.7} {Earth 1 1} {Mars 0.107 1.5}]
|
|
// By decreasing distance: [{Mars 0.107 1.5} {Earth 1 1} {Venus 0.815 0.7} {Mercury 0.055 0.4}]
|
|
}
|