github.com/camlistore/go4@v0.0.0-20200104003542-c7e774b10ea0/sort/example_multi_test.go (about)

     1  // +build go1.6
     2  
     3  // Copyright 2013 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package sort_test
     8  
     9  import (
    10  	"fmt"
    11  	"sort"
    12  )
    13  
    14  // A Change is a record of source code changes, recording user, language, and delta size.
    15  type Change struct {
    16  	user     string
    17  	language string
    18  	lines    int
    19  }
    20  
    21  type lessFunc func(p1, p2 *Change) bool
    22  
    23  // multiSorter implements the Sort interface, sorting the changes within.
    24  type multiSorter struct {
    25  	changes []Change
    26  	less    []lessFunc
    27  }
    28  
    29  // Sort sorts the argument slice according to the less functions passed to OrderedBy.
    30  func (ms *multiSorter) Sort(changes []Change) {
    31  	ms.changes = changes
    32  	sort.Sort(ms)
    33  }
    34  
    35  // OrderedBy returns a Sorter that sorts using the less functions, in order.
    36  // Call its Sort method to sort the data.
    37  func OrderedBy(less ...lessFunc) *multiSorter {
    38  	return &multiSorter{
    39  		less: less,
    40  	}
    41  }
    42  
    43  // Len is part of sort.Interface.
    44  func (ms *multiSorter) Len() int {
    45  	return len(ms.changes)
    46  }
    47  
    48  // Swap is part of sort.Interface.
    49  func (ms *multiSorter) Swap(i, j int) {
    50  	ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]
    51  }
    52  
    53  // Less is part of sort.Interface. It is implemented by looping along the
    54  // less functions until it finds a comparison that is either Less or
    55  // !Less. Note that it can call the less functions twice per call. We
    56  // could change the functions to return -1, 0, 1 and reduce the
    57  // number of calls for greater efficiency: an exercise for the reader.
    58  func (ms *multiSorter) Less(i, j int) bool {
    59  	p, q := &ms.changes[i], &ms.changes[j]
    60  	// Try all but the last comparison.
    61  	var k int
    62  	for k = 0; k < len(ms.less)-1; k++ {
    63  		less := ms.less[k]
    64  		switch {
    65  		case less(p, q):
    66  			// p < q, so we have a decision.
    67  			return true
    68  		case less(q, p):
    69  			// p > q, so we have a decision.
    70  			return false
    71  		}
    72  		// p == q; try the next comparison.
    73  	}
    74  	// All comparisons to here said "equal", so just return whatever
    75  	// the final comparison reports.
    76  	return ms.less[k](p, q)
    77  }
    78  
    79  var changes = []Change{
    80  	{"gri", "Go", 100},
    81  	{"ken", "C", 150},
    82  	{"glenda", "Go", 200},
    83  	{"rsc", "Go", 200},
    84  	{"r", "Go", 100},
    85  	{"ken", "Go", 200},
    86  	{"dmr", "C", 100},
    87  	{"r", "C", 150},
    88  	{"gri", "Smalltalk", 80},
    89  }
    90  
    91  // ExampleMultiKeys demonstrates a technique for sorting a struct type using different
    92  // sets of multiple fields in the comparison. We chain together "Less" functions, each of
    93  // which compares a single field.
    94  func Example_sortMultiKeys() {
    95  	// Closures that order the Change structure.
    96  	user := func(c1, c2 *Change) bool {
    97  		return c1.user < c2.user
    98  	}
    99  	language := func(c1, c2 *Change) bool {
   100  		return c1.language < c2.language
   101  	}
   102  	increasingLines := func(c1, c2 *Change) bool {
   103  		return c1.lines < c2.lines
   104  	}
   105  	decreasingLines := func(c1, c2 *Change) bool {
   106  		return c1.lines > c2.lines // Note: > orders downwards.
   107  	}
   108  
   109  	// Simple use: Sort by user.
   110  	OrderedBy(user).Sort(changes)
   111  	fmt.Println("By user:", changes)
   112  
   113  	// More examples.
   114  	OrderedBy(user, increasingLines).Sort(changes)
   115  	fmt.Println("By user,<lines:", changes)
   116  
   117  	OrderedBy(user, decreasingLines).Sort(changes)
   118  	fmt.Println("By user,>lines:", changes)
   119  
   120  	OrderedBy(language, increasingLines).Sort(changes)
   121  	fmt.Println("By language,<lines:", changes)
   122  
   123  	OrderedBy(language, increasingLines, user).Sort(changes)
   124  	fmt.Println("By language,<lines,user:", changes)
   125  
   126  	// Output:
   127  	// By user: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
   128  	// By user,<lines: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
   129  	// By user,>lines: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken Go 200} {ken C 150} {r C 150} {r Go 100} {rsc Go 200}]
   130  	// By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {r Go 100} {gri Go 100} {ken Go 200} {glenda Go 200} {rsc Go 200} {gri Smalltalk 80}]
   131  	// By language,<lines,user: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]
   132  
   133  }