131 lines · 4.0 KB · Go
RawDownload
// Copyright 2013 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file. package sort_test import (	"fmt"	"sort") // A Change is a record of source code changes, recording user, language, and delta size.type Change struct {	user     string	language string	lines    int} type lessFunc func(p1, p2 *Change) bool // multiSorter implements the Sort interface, sorting the changes within.type multiSorter struct {	changes []Change	less    []lessFunc} // Sort sorts the argument slice according to the less functions passed to OrderedBy.func (ms *multiSorter) Sort(changes []Change) {	ms.changes = changes	sort.Sort(ms)} // OrderedBy returns a Sorter that sorts using the less functions, in order.// Call its Sort method to sort the data.func OrderedBy(less ...lessFunc) *multiSorter {	return &multiSorter{		less: less,	}} // Len is part of sort.Interface.func (ms *multiSorter) Len() int {	return len(ms.changes)} // Swap is part of sort.Interface.func (ms *multiSorter) Swap(i, j int) {	ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]} // Less is part of sort.Interface. It is implemented by looping along the// less functions until it finds a comparison that is either Less or// !Less. Note that it can call the less functions twice per call. We// could change the functions to return -1, 0, 1 and reduce the// number of calls for greater efficiency: an exercise for the reader.func (ms *multiSorter) Less(i, j int) bool {	p, q := &ms.changes[i], &ms.changes[j]	// Try all but the last comparison.	var k int	for k = 0; k < len(ms.less)-1; k++ {		less := ms.less[k]		switch {		case less(p, q):			// p < q, so we have a decision.			return true		case less(q, p):			// p > q, so we have a decision.			return false		}		// p == q; try the next comparison.	}	// All comparisons to here said "equal", so just return whatever	// the final comparison reports.	return ms.less[k](p, q)} var changes = []Change{	{"gri", "Go", 100},	{"ken", "C", 150},	{"glenda", "Go", 200},	{"rsc", "Go", 200},	{"r", "Go", 100},	{"ken", "Go", 200},	{"dmr", "C", 100},	{"r", "C", 150},	{"gri", "Smalltalk", 80},} // ExampleMultiKeys demonstrates a technique for sorting a struct type using different// sets of multiple fields in the comparison. We chain together "Less" functions, each of// which compares a single field.func Example_sortMultiKeys() {	// Closures that order the Change structure.	user := func(c1, c2 *Change) bool {		return c1.user < c2.user	}	language := func(c1, c2 *Change) bool {		return c1.language < c2.language	}	increasingLines := func(c1, c2 *Change) bool {		return c1.lines < c2.lines	}	decreasingLines := func(c1, c2 *Change) bool {		return c1.lines > c2.lines // Note: > orders downwards.	} 	// Simple use: Sort by user.	OrderedBy(user).Sort(changes)	fmt.Println("By user:", changes) 	// More examples.	OrderedBy(user, increasingLines).Sort(changes)	fmt.Println("By user,<lines:", changes) 	OrderedBy(user, decreasingLines).Sort(changes)	fmt.Println("By user,>lines:", changes) 	OrderedBy(language, increasingLines).Sort(changes)	fmt.Println("By language,<lines:", changes) 	OrderedBy(language, increasingLines, user).Sort(changes)	fmt.Println("By language,<lines,user:", changes) 	// Output:	// 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}]	// 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}]	// 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}]	// 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}]	// 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}] }