Golang: Сортировка срезов
Сортировка — одна из самых распространённых операций над коллекциями. В Go для работы со срезами предусмотрены готовые функции в пакете slices, которые упрощают сортировку без необходимости писать собственные алгоритмы.
Сортировка по возрастанию
Для сортировки среза с элементами любого упорядоченного типа (например, int, string) используется функция slices.Sort():
import (
"fmt"
"slices"
)
func main() {
nums := []int{5, 2, 9, 1, 3}
slices.Sort(nums)
fmt.Println(nums) // => [1 2 3 5 9]
}Изменяется ли исходный срез?
Важно помнить, что slices.Sort() изменяет исходный срез на месте. После вызова slices.Sort(nums) срез nums будет отсортирован, а новый срез не создаётся. Если нужно получить новый отсортированный срез, используйте slices.Sorted(), которая возвращает копию с отсортированными элементами:
original := []int{5, 2, 9}
sorted := slices.Sorted(original)
fmt.Println(original)
// => [5 2 9]
fmt.Println(sorted)
// => [2 5 9]Проверка, отсортирован ли срез
Иногда нужно проверить, находится ли срез в порядке возрастания. Для этого есть slices.IsSorted():
nums := []int{1, 2, 3}
fmt.Println(slices.IsSorted(nums)) // => trueСортировка строк
Срез строк сортируется аналогично:
words := []string{"banana", "apple", "cherry"}
slices.Sort(words)
fmt.Println(words) // => [apple banana cherry]Сортировка выполняется в лексикографическом порядке (по Unicode-кодам символов).
Сортировка с пользовательской логикой
Если нужно задать собственное правило сортировки, можно использовать slices.SortFunc().
Например, сортировка строк по длине:
slices.SortFunc(words, func(a, b string) int {
// по длине
return len(a) - len(b)
})
fmt.Println(words) // => [apple banana cherry]Функция-компаратор должна возвращать:
- Отрицательное значение, если
a < b, - Ноль, если
a == b, - Положительное значение, если
a > b.
Обратный порядок
Чтобы отсортировать в обратном порядке, можно:
- Отсортировать по возрастанию.
- Развернуть срез с помощью
slices.Reverse().
nums := []int{5, 2, 9, 1, 3}
slices.Sort(nums)
slices.Reverse(nums)
fmt.Println(nums) // => [9 5 3 2 1]Минимальные и максимальные значения
Пакет slices также предоставляет функции для нахождения минимального и максимального элементов:
nums := []int{5, 2, 9, 1, 3}
fmt.Println(slices.Min(nums)) // => 1
fmt.Println(slices.Max(nums)) // => 9Вывод
- Функции
slices.Sort()иslices.SortFunc()изменяют исходный срез. - Если нужен новый отсортированный срез, используйте
slices.Clone()перед сортировкой. - Для кастомных правил сортировки —
slices.SortFunc(). - Проверить порядок можно через
slices.IsSorted(). - Минимум и максимум вычисляются с помощью
slices.Min()иslices.Max().
Задание
Реализуйте функцию SortOrdersByCustomerID(orders []Order) []Order, которая возвращает новый срез заказов, отсортированных по ID клиента (от меньшего к большему). Если у нескольких заказов одинаковый CustomerID — сортируйте их по цене (от меньшей к большей).
Структура Order уже определена:
type Order struct {
CustomerID int
Price int
}Оригинальный срез изменяться не должен.
Примеры:
orders := []Order{
{CustomerID: 3, Price: 200},
{CustomerID: 1, Price: 300},
{CustomerID: 3, Price: 100},
}
result := SortOrdersByCustomerID(orders)
fmt.Println(result)
// [{1 300} {3 100} {3 200}]
fmt.Println(orders)
// [{3 200} {1 300} {3 100}] — оригинал не изменилсяПолезное
Ваше упражнение проверяется по этим тестам
// Тесты
package solution
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSortOrdersByCustomerID(t *testing.T) {
tests := []struct {
name string
input []Order
expected []Order
}{
{
name: "Sort by CustomerID",
input: []Order{
{CustomerID: 3, Price: 200},
{CustomerID: 1, Price: 300},
{CustomerID: 2, Price: 100},
},
expected: []Order{
{CustomerID: 1, Price: 300},
{CustomerID: 2, Price: 100},
{CustomerID: 3, Price: 200},
},
},
{
name: "Sort by CustomerID and price",
input: []Order{
{CustomerID: 2, Price: 300},
{CustomerID: 2, Price: 100},
{CustomerID: 1, Price: 500},
},
expected: []Order{
{CustomerID: 1, Price: 500},
{CustomerID: 2, Price: 100},
{CustomerID: 2, Price: 300},
},
},
{
name: "Empty slice",
input: []Order{},
expected: []Order{},
},
{
name: "Single element",
input: []Order{{CustomerID: 1, Price: 100}},
expected: []Order{{CustomerID: 1, Price: 100}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := SortOrdersByCustomerID(tt.input)
assert.Equal(t, tt.expected, result)
assert.Equal(t, tt.input, tt.input, "original slice should remain unchanged")
})
}
}Решение учителя откроется через:
20:00
