Skip to content

Commit 439f692

Browse files
authored
Merge branch 'main' into feat/sorting-exercise
2 parents 3d54262 + e5420af commit 439f692

4 files changed

Lines changed: 264 additions & 0 deletions

File tree

internal/exercises/catalog.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,13 @@ projects:
227227
- "Use Go's `time.Unix()` to convert an epoch to time."
228228
- "Use `t.Unix()` to convert time back to epoch."
229229
- "Remember Go’s `time.Parse` can help parse date strings."
230+
231+
- slug: 37_sorting_by_functions
232+
title: "Sorting by Functions"
233+
difficulty: beginner
234+
topics: ["slices", "sorting", "functions"]
235+
hints:
236+
- "Implement sort.Interface with Len(), Less(), and Swap() methods"
237+
- "Create custom slice types like ByName and ByAge (e.g., type ByName []Person)"
238+
- "Use sort.Sort() to sort slices with your custom comparison logic"
239+
- "Remember to make copies of slices to avoid modifying the original"
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package sorting_by_functions
2+
3+
import "sort"
4+
5+
// Person represents a person with a name and age
6+
type Person struct {
7+
Name string
8+
Age int
9+
}
10+
11+
// ByName is a type for sorting Person slices by name
12+
type ByName []Person
13+
14+
// Implement sort.Interface for ByName
15+
func (b ByName) Len() int {
16+
return len(b)
17+
}
18+
19+
func (b ByName) Swap(i, j int) {
20+
b[i], b[j] = b[j], b[i]
21+
}
22+
23+
func (b ByName) Less(i, j int) bool {
24+
return b[i].Name < b[j].Name
25+
}
26+
27+
// ByAge is a type for sorting Person slices by age
28+
type ByAge []Person
29+
30+
// Implement sort.Interface for ByAge
31+
func (b ByAge) Len() int {
32+
return len(b)
33+
}
34+
35+
func (b ByAge) Swap(i, j int) {
36+
b[i], b[j] = b[j], b[i]
37+
}
38+
39+
func (b ByAge) Less(i, j int) bool {
40+
return b[i].Age < b[j].Age
41+
}
42+
43+
// SortByName sorts a slice of Person by name using the custom ByName type
44+
func SortByName(people []Person) []Person {
45+
// Create a copy of the slice to avoid modifying the original
46+
result := make([]Person, len(people))
47+
copy(result, people)
48+
49+
// Sort the copy by name
50+
sort.Sort(ByName(result))
51+
52+
return result
53+
}
54+
55+
// SortByAge sorts a slice of Person by age using the custom ByAge type
56+
func SortByAge(people []Person) []Person {
57+
// Create a copy of the slice to avoid modifying the original
58+
result := make([]Person, len(people))
59+
copy(result, people)
60+
61+
// Sort the copy by age
62+
sort.Sort(ByAge(result))
63+
64+
return result
65+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package sorting_by_functions
2+
3+
// import sort package
4+
5+
// TODO:
6+
// - Implement the sort.Interface methods for ByName and ByAge
7+
// - Complete SortByName and SortByAge functions to sort slices using custom comparison
8+
9+
// Person represents a person with a name and age
10+
type Person struct {
11+
Name string
12+
Age int
13+
}
14+
15+
// ByName is a type for sorting Person slices by name
16+
type ByName []Person
17+
18+
// Implement sort.Interface for ByName
19+
func (b ByName) Len() int {
20+
// TODO: return the length of the slice
21+
return 0
22+
}
23+
24+
func (b ByName) Swap(i, j int) {
25+
// TODO: swap elements at positions i and j
26+
}
27+
28+
func (b ByName) Less(i, j int) bool {
29+
// TODO: return true if element at i should come before element at j (compare by name)
30+
return false
31+
}
32+
33+
// ByAge is a type for sorting Person slices by age
34+
type ByAge []Person
35+
36+
// Implement sort.Interface for ByAge
37+
func (b ByAge) Len() int {
38+
// TODO: return the length of the slice
39+
return 0
40+
}
41+
42+
func (b ByAge) Swap(i, j int) {
43+
// TODO: swap elements at positions i and j
44+
}
45+
46+
func (b ByAge) Less(i, j int) bool {
47+
// TODO: return true if element at i should come before element at j (compare by age)
48+
return false
49+
}
50+
51+
// SortByName sorts a slice of Person by name using the custom ByName type
52+
func SortByName(people []Person) []Person {
53+
// TODO: create a copy of the slice and sort it by name
54+
// Hint: use sort.Sort() with ByName type
55+
return nil
56+
}
57+
58+
// SortByAge sorts a slice of Person by age using the custom ByAge type
59+
func SortByAge(people []Person) []Person {
60+
// TODO: create a copy of the slice and sort it by age
61+
// Hint: use sort.Sort() with ByAge type
62+
return nil
63+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package sorting_by_functions
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestSortByName(t *testing.T) {
9+
people := []Person{
10+
{Name: "Charlie", Age: 30},
11+
{Name: "Alice", Age: 25},
12+
{Name: "Bob", Age: 35},
13+
}
14+
15+
expected := []Person{
16+
{Name: "Alice", Age: 25},
17+
{Name: "Bob", Age: 35},
18+
{Name: "Charlie", Age: 30},
19+
}
20+
21+
result := SortByName(people)
22+
if !reflect.DeepEqual(result, expected) {
23+
t.Errorf("SortByName() = %v, want %v", result, expected)
24+
}
25+
26+
// Ensure original slice is not modified
27+
originalExpected := []Person{
28+
{Name: "Charlie", Age: 30},
29+
{Name: "Alice", Age: 25},
30+
{Name: "Bob", Age: 35},
31+
}
32+
if !reflect.DeepEqual(people, originalExpected) {
33+
t.Errorf("Original slice was modified: %v, want %v", people, originalExpected)
34+
}
35+
}
36+
37+
func TestSortByAge(t *testing.T) {
38+
people := []Person{
39+
{Name: "Charlie", Age: 30},
40+
{Name: "Alice", Age: 25},
41+
{Name: "Bob", Age: 35},
42+
}
43+
44+
expected := []Person{
45+
{Name: "Alice", Age: 25},
46+
{Name: "Charlie", Age: 30},
47+
{Name: "Bob", Age: 35},
48+
}
49+
50+
result := SortByAge(people)
51+
if !reflect.DeepEqual(result, expected) {
52+
t.Errorf("SortByAge() = %v, want %v", result, expected)
53+
}
54+
55+
// Ensure original slice is not modified
56+
originalExpected := []Person{
57+
{Name: "Charlie", Age: 30},
58+
{Name: "Alice", Age: 25},
59+
{Name: "Bob", Age: 35},
60+
}
61+
if !reflect.DeepEqual(people, originalExpected) {
62+
t.Errorf("Original slice was modified: %v, want %v", people, originalExpected)
63+
}
64+
}
65+
66+
func TestByNameInterface(t *testing.T) {
67+
people := []Person{
68+
{Name: "Charlie", Age: 30},
69+
{Name: "Alice", Age: 25},
70+
{Name: "Bob", Age: 35},
71+
}
72+
73+
byName := ByName(people)
74+
75+
// Test Len
76+
if byName.Len() != 3 {
77+
t.Errorf("ByName.Len() = %d, want 3", byName.Len())
78+
}
79+
80+
// Test Less
81+
if !byName.Less(1, 0) { // "Alice" < "Charlie"
82+
t.Errorf("ByName.Less(1, 0) should be true (Alice < Charlie)")
83+
}
84+
if byName.Less(0, 1) { // "Charlie" > "Alice"
85+
t.Errorf("ByName.Less(0, 1) should be false (Charlie > Alice)")
86+
}
87+
88+
// Test Swap
89+
original := make([]Person, len(people))
90+
copy(original, people)
91+
byName.Swap(0, 1)
92+
if byName[0].Name != original[1].Name || byName[1].Name != original[0].Name {
93+
t.Errorf("ByName.Swap(0, 1) did not swap correctly")
94+
}
95+
}
96+
97+
func TestByAgeInterface(t *testing.T) {
98+
people := []Person{
99+
{Name: "Charlie", Age: 30},
100+
{Name: "Alice", Age: 25},
101+
{Name: "Bob", Age: 35},
102+
}
103+
104+
byAge := ByAge(people)
105+
106+
// Test Len
107+
if byAge.Len() != 3 {
108+
t.Errorf("ByAge.Len() = %d, want 3", byAge.Len())
109+
}
110+
111+
// Test Less
112+
if !byAge.Less(1, 0) { // 25 < 30
113+
t.Errorf("ByAge.Less(1, 0) should be true (25 < 30)")
114+
}
115+
if byAge.Less(0, 1) { // 30 > 25
116+
t.Errorf("ByAge.Less(0, 1) should be false (30 > 25)")
117+
}
118+
119+
// Test Swap
120+
original := make([]Person, len(people))
121+
copy(original, people)
122+
byAge.Swap(0, 1)
123+
if byAge[0].Age != original[1].Age || byAge[1].Age != original[0].Age {
124+
t.Errorf("ByAge.Swap(0, 1) did not swap correctly")
125+
}
126+
}

0 commit comments

Comments
 (0)