Sort
To sort in Go we use the "sort" package. We sort strings alphabetically with Strings()
. For complex things, we use Sort
and define an interface
(with Len, Less and Swap).
We can sort from low to high (ascending) or high to low (descending). And we can even test to see if a collection is already sorted.
This method implements an ascending (low to high, alphabetical) sort of strings. So they go from A to Z. We must add the "sort" package to our import block.
package main import ( "fmt" "sort" ) func main() { animals := []string{"cat", "bird", "zebra", "fox"} // Sort strings. sort.Strings(animals) // Print results. fmt.Println(animals) }[bird cat fox zebra]
Sort
strings by lengthHere we specify how elements in a slice are sorted. We use the "type" keyword to create a type. We implement the sort.Interface
on our ByLen
type.
Len()
is required by sort.Interface
, and it is used by the sort.Sort
func
.Less()
compares two elements of the type. Here we use custom code to compare the lengths of two elements.Swap()
is used by the sorting algorithm to swap two elements in the collection.package main import ( "fmt" "sort" ) // Implement length-based sort with ByLen type. type ByLen []string func (a ByLen) Len() int { return len(a) } func (a ByLen) Less(i, j int) bool { return len(a[i]) < len(a[j]) } func (a ByLen) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func main() { // These elements are not sorted. elements := []string{"ruby", "python", "java", "go"} // Sort the elements by length. sort.Sort(ByLen(elements)) // Print results. fmt.Println(elements) }[go ruby java python]
Sort
keys in mapA map cannot be sorted directly. But if we get a slice of the keys from a map, we can sort that slice and loop over it, accessing the map's values.
package main import ( "fmt" "sort" ) func main() { codes := map[string]int{ "xyz": 1, "ghi": 1, "abc": 1, "def": 1, } // Get keys from map. keys := []string{} for key, _ := range codes { keys = append(keys, key) } // Sort string keys. sort.Strings(keys) // Loop over sorted key-value pairs. for i := range keys { key := keys[i] value := codes[key] fmt.Printf("%v = %v", key, value) fmt.Println() } }abc = 1 def = 1 ghi = 1 xyz = 1
StringsAreSorted
Sometimes we want to see if a slice is already sorted. With StringsAreSorted
we pass in a string
slice and get a bool
—true if the slice is in sorted order.
string
slices are already sorted. An empty slice is considered sorted.package main import ( "fmt" "sort" ) func main() { animalsSorted := []string{"bird", "cat", "dog"} animalsEmpty := []string{} // Test to see if the string slices are sorted. if sort.StringsAreSorted(animalsSorted) { fmt.Println("A") } if sort.StringsAreSorted(animalsEmpty) { fmt.Println("B") } }A B
StringsAreSorted
, benchmarkHere we introduce a method called EnsureSorted
. This method sorts the string
slice if StringsAreSorted
returns false.
StringsAreSorted
method before using sort.Strings
.sort.Strings
directly, without testing if the slice needs to be sorted first.EnsureSorted
method with StringsAreSorted
takes about the same amount of time assorting an already-sorted slice.EnsureSorted
. But if we cache the result of StringsAreSorted
and avoid calling it repeatedly, this could help.package main import ( "fmt" "sort" "time" ) func EnsureSorted(elements []string) { if !sort.StringsAreSorted(elements) { sort.Strings(elements); } } func main() { elements := []string{"aaa", "b", "c", "ddd", "e"} t0 := time.Now() // Version 1: sort if StringsAreSorted returns false. for i := 0; i < 10000000; i++ { EnsureSorted(elements) } t1 := time.Now() // Version 2: always sort. for i := 0; i < 10000000; i++ { sort.Strings(elements) } t2 := time.Now() // Results. fmt.Println(t1.Sub(t0)) fmt.Println(t2.Sub(t1)) }2.9944054s EnsureSorted 2.9071126s strings.Sort
The Ints method has a parallel effect to Strings—it sorts Ints from low to high in numeric order. We must pass Ints()
an int
slice.
package main import ( "fmt" "sort" ) func main() { numbers := []int{10, 0, 20, 1} // Sort ints in ascending order. sort.Ints(numbers) fmt.Println(numbers) }[0 1 10 20]
IntsAreSorted
This method returns a bool
and tells us whether an int
slice is sorted. An empty slice is considered sorted (it is not unsorted).
IntsAreSorted
, we can test the result in an if
-statement. If false, we could call Ints to ensure the values are sorted.package main import ( "fmt" "sort" ) func main() { numbersUnsorted := []int{100, 1, 5} numbersSorted := []int{1, 5, 100} numbersEmpty := []int{} if sort.IntsAreSorted(numbersUnsorted) { // Not reached. fmt.Println("A") } if sort.IntsAreSorted(numbersSorted) { fmt.Println("B") } if sort.IntsAreSorted(numbersEmpty) { fmt.Println("C") } }B C
Sort
methodsTo sort a list of files by their sizes in bytes, we can act directly upon the FileInfo
returned by Readdir
. For alphanumeric sorting, we can sort strings by their interior chunks.
With the sort Interface, and its funcs Len, Less and Swap, we can sort elements in more complex ways. Sorting in Go operates on slices.