blob: 648f919e68dbd9d353d9fe2b52784b928ac8ec93 [file] [log] [blame]
Rob Pike2c2934e2013-02-26 17:17:44 -08001// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package sort_test
6
7import (
8 "fmt"
9 "sort"
10)
11
12// A couple of type definitions to make the units clear.
Volker Dobler73c21b12013-02-27 10:44:50 -080013type earthMass float64
Rob Pike2c2934e2013-02-26 17:17:44 -080014type au float64
15
16// A Planet defines the properties of a solar system object.
17type Planet struct {
18 name string
Volker Dobler73c21b12013-02-27 10:44:50 -080019 mass earthMass
Rob Pike2c2934e2013-02-26 17:17:44 -080020 distance au
21}
22
23// By is the type of a "less" function that defines the ordering of its Planet arguments.
24type By func(p1, p2 *Planet) bool
25
26// Sort is a method on the function type, By, that sorts the argument slice according to the function.
27func (by By) Sort(planets []Planet) {
28 ps := &planetSorter{
29 planets: planets,
30 by: by, // The Sort method's receiver is the function (closure) that defines the sort order.
31 }
32 sort.Sort(ps)
33}
34
35// planetSorter joins a By function and a slice of Planets to be sorted.
36type planetSorter struct {
37 planets []Planet
38 by func(p1, p2 *Planet) bool // Closure used in the Less method.
39}
40
41// Len is part of sort.Interface.
42func (s *planetSorter) Len() int {
43 return len(s.planets)
44}
45
46// Swap is part of sort.Interface.
47func (s *planetSorter) Swap(i, j int) {
48 s.planets[i], s.planets[j] = s.planets[j], s.planets[i]
49}
50
51// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
52func (s *planetSorter) Less(i, j int) bool {
53 return s.by(&s.planets[i], &s.planets[j])
54}
55
56var planets = []Planet{
57 {"Mercury", 0.055, 0.4},
58 {"Venus", 0.815, 0.7},
59 {"Earth", 1.0, 1.0},
60 {"Mars", 0.107, 1.5},
61}
62
63// ExampleSortKeys demonstrates a technique for sorting a struct type using programmable sort criteria.
64func Example_sortKeys() {
65 // Closures that order the Planet structure.
66 name := func(p1, p2 *Planet) bool {
67 return p1.name < p2.name
68 }
69 mass := func(p1, p2 *Planet) bool {
70 return p1.mass < p2.mass
71 }
72 distance := func(p1, p2 *Planet) bool {
73 return p1.distance < p2.distance
74 }
75 decreasingDistance := func(p1, p2 *Planet) bool {
Tom Levy2bba2672017-08-22 17:10:46 +120076 return distance(p2, p1)
Rob Pike2c2934e2013-02-26 17:17:44 -080077 }
78
79 // Sort the planets by the various criteria.
80 By(name).Sort(planets)
81 fmt.Println("By name:", planets)
82
83 By(mass).Sort(planets)
84 fmt.Println("By mass:", planets)
85
86 By(distance).Sort(planets)
87 fmt.Println("By distance:", planets)
88
89 By(decreasingDistance).Sort(planets)
90 fmt.Println("By decreasing distance:", planets)
91
92 // Output: By name: [{Earth 1 1} {Mars 0.107 1.5} {Mercury 0.055 0.4} {Venus 0.815 0.7}]
93 // By mass: [{Mercury 0.055 0.4} {Mars 0.107 1.5} {Venus 0.815 0.7} {Earth 1 1}]
94 // By distance: [{Mercury 0.055 0.4} {Venus 0.815 0.7} {Earth 1 1} {Mars 0.107 1.5}]
95 // By decreasing distance: [{Mars 0.107 1.5} {Earth 1 1} {Venus 0.815 0.7} {Mercury 0.055 0.4}]
96}