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
