Welcome to Custom Sorting in Go. In this lesson, we'll explore how to use slices and the sort
package in Go to organize data structures with custom sorting mechanisms. By applying custom sorting functions, we can enhance data organization and access, dictating the order of elements in our collections.
Sorting collections involves arranging elements in a particular order, making operations like searching within a range more efficient. In Go, while a map
doesn't maintain order, sorting can be achieved by extracting keys into a slice and using the sort
package:
Go1package main 2 3import ( 4 "fmt" 5 "sort" 6) 7 8func main() { 9 m := map[string]int{"a": 1, "c": 3, "b": 2} 10 keys := make([]string, 0, len(m)) 11 12 for k := range m { 13 keys = append(keys, k) 14 } 15 16 sort.Strings(keys) 17 18 for _, k := range keys { 19 fmt.Printf("%s=%d\n", k, m[k]) // Outputs "a=1", "b=2", "c=3" 20 } 21}
Structs in Go allow us to create complex data types that encapsulate multiple properties, suitable for representing entities like a Person
or a Book
. Structs serve as blueprints for creating instances with specific data.
Go1package main 2 3import "fmt" 4 5type Person struct { 6 Name string 7 Age int 8} 9 10func main() { 11 person := Person{Name: "John Doe", Age: 30} 12 fmt.Println(person.Name) // Outputs "John Doe" 13 fmt.Println(person.Age) // Outputs 30 14}
Using structs along with slices allows us to organize complex data. Consider using structs with slices in lieu of data structures that require sorted keys:
Go1package main 2 3import ( 4 "fmt" 5 "sort" 6) 7 8type Person struct { 9 Name string 10 Age int 11} 12 13func main() { 14 people := []Person{ 15 {"John", 30}, 16 {"Alice", 25}, 17 } 18 19 sort.Slice(people, func(i, j int) bool { 20 if people[i].Age != people[j].Age { 21 return people[i].Age < people[j].Age 22 } 23 return people[i].Name < people[j].Name 24 }) 25 26 for _, person := range people { 27 fmt.Printf("%s is %d years old\n", person.Name, person.Age) 28 } 29 // Output: 30 // Alice is 25 years old 31 // John is 30 years old 32}
In this example, we create a Person
struct and sort a slice of Person
using custom criteria defined in a sort.Slice
function. We define custom sorting criteria using a lambda function, which allows us to specify the logic for determining the order of the elements. The lambda function is passed as an argument to the sort.Slice
function, where it takes two indices, i
and j
, and returns true
if the element at index i
should appear before the element at index j
. This flexibility lets us sort the Person
slice first by Age
and then by Name
if the ages are equal.
In Go, while the sort.Slice
function provides straightforward sorting with custom comparator functions, the sort.Sort
function offers a more customizable approach. This method requires you to implement the sort.Interface
for the collection you want to sort, which involves defining three essential methods: Len()
, Swap()
, and Less()
.
Go1package main 2 3import ( 4 "fmt" 5 "sort" 6) 7 8type Person struct { 9 Name string 10 Age int 11} 12 13type ByAge []Person 14 15func (a ByAge) Len() int { return len(a) } 16func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 17func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age } 18 19func main() { 20 people := []Person{ 21 {"John", 30}, 22 {"Alice", 25}, 23 } 24 25 sort.Sort(ByAge(people)) 26 27 for _, person := range people { 28 fmt.Printf("%s is %d years old\n", person.Name, person.Age) 29 } 30 // Output: 31 // Alice is 25 years old 32 // John is 30 years old 33}
In this example, we define a new type ByAge
which is a slice of Person
. We then satisfy the sort.Interface
by implementing Len()
, Swap()
, and Less()
methods. Len()
returns the number of elements, Swap()
exchanges elements at given indices, and Less()
determines the sorting order, here sorting by Age
. By declaring the slice with ByAge
and passing it to sort.Sort
, we sort the people
slice according to the logic in the Less()
method. This approach allows fine-grained control over sorting operations using Go's interface mechanism.
We've examined how to use slices and the sort
package in Go to achieve sorted data similar to sorted dictionaries. By leveraging Go's sorting functions and customizing sorting criteria, we can maintain ordered collections. Structs facilitate the organization of complex data, allowing for efficient manipulation and retrieval based on sorted attributes. Prepare for hands-on exercises to reinforce these concepts.