Home | History | Annotate | Download | only in sort
      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.
     13 type earthMass float64
     14 type au float64
     15 
     16 // A Planet defines the properties of a solar system object.
     17 type Planet struct {
     18 	name     string
     19 	mass     earthMass
     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 {
     76 		return distance(p2, p1)
     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 }
     97