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 }