Rob Pike | 2c2934e | 2013-02-26 17:17:44 -0800 | [diff] [blame] | 1 | // 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 | |
| 5 | package sort_test |
| 6 | |
| 7 | import ( |
| 8 | "fmt" |
| 9 | "sort" |
| 10 | ) |
| 11 | |
| 12 | // A couple of type definitions to make the units clear. |
Volker Dobler | 73c21b1 | 2013-02-27 10:44:50 -0800 | [diff] [blame] | 13 | type earthMass float64 |
Rob Pike | 2c2934e | 2013-02-26 17:17:44 -0800 | [diff] [blame] | 14 | type au float64 |
| 15 | |
| 16 | // A Planet defines the properties of a solar system object. |
| 17 | type Planet struct { |
| 18 | name string |
Volker Dobler | 73c21b1 | 2013-02-27 10:44:50 -0800 | [diff] [blame] | 19 | mass earthMass |
Rob Pike | 2c2934e | 2013-02-26 17:17:44 -0800 | [diff] [blame] | 20 | distance au |
| 21 | } |
| 22 | |
| 23 | // By is the type of a "less" function that defines the ordering of its Planet arguments. |
| 24 | type 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. |
| 27 | func (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. |
| 36 | type 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. |
| 42 | func (s *planetSorter) Len() int { |
| 43 | return len(s.planets) |
| 44 | } |
| 45 | |
| 46 | // Swap is part of sort.Interface. |
| 47 | func (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. |
| 52 | func (s *planetSorter) Less(i, j int) bool { |
| 53 | return s.by(&s.planets[i], &s.planets[j]) |
| 54 | } |
| 55 | |
| 56 | var 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. |
| 64 | func 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 Levy | 2bba267 | 2017-08-22 17:10:46 +1200 | [diff] [blame] | 76 | return distance(p2, p1) |
Rob Pike | 2c2934e | 2013-02-26 17:17:44 -0800 | [diff] [blame] | 77 | } |
| 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 | } |