Ответ
В Go идиоматический способ сортировки — использование пакета sort. Он предоставляет эффективные и гибкие инструменты для работы с любыми типами данных.
В основе пакета лежит интерфейс sort.Interface:
_type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
_```
Любой тип, реализующий этот интерфейс, может быть отсортирован функцией `sort.Sort()`.
### Способы сортировки пользовательских типов:
**1. Реализация `sort.Interface` (классический способ)**
Нужно определить три метода для вашего типа-слайса. Это полезно, когда сортировка является основным поведением для типа.
```go
_type User struct {
Name string
Age int
}
// ByAge реализует sort.Interface для []User по полю Age
_type ByAge []User
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func main() {
users := []User{
{"Alice", 25},
{"Bob", 20},
}
sort.Sort(ByAge(users))
fmt.Println(users) // [{Bob 20} {Alice 25}]
}
_```
**2. Использование `sort.Slice` (современный и более гибкий способ)**
Эта функция, появившаяся в Go 1.8, не требует реализации интерфейса. Она принимает слайс и функцию `less` в качестве аргументов. Это удобнее для одноразовых или динамических сортировок.
```go
_func main() {
users := []User{
{"Alice", 25},
{"Bob", 20},
}
// Сортировка по имени
sort.Slice(users, func(i, j int) bool {
return users[i].Name < users[j].Name
})
fmt.Println(users) // [{Alice 25} {Bob 20}]
}
_```
### Алгоритм и готовые функции
- **Алгоритм**: Стандартная библиотека Go использует **pdqsort** (Pattern-Defeating Quicksort), который является гибридом быстрой сортировки, пирамидальной сортировки и сортировки вставками. Он показывает отличную производительность в большинстве случаев.
- **Готовые функции**: Для базовых типов существуют удобные обертки, такие как `sort.Ints()`, `sort.Float64s()` и `sort.Strings()`, которые используют те же эффективные алгоритмы. Ответ 18+ 🔞
Ну что за дичь, а? Смотри, в Го сортировка — это не какая-то там шаманская пляска с бубном, а вполне себе приличный пакет sort. Он тебе даёт такие инструменты, что хоть слона упорядочивай, если, конечно, у тебя слайс слонов, а не какая-нибудь хуйня.
Вот смотри, в самом сердце этого цирка лежит интерфейс sort.Interface:
_type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
_```
Если твой тип на это согласится — реализует три этих метода — то `sort.Sort()` его отсортирует так, что мама не горюй. Алгоритм там, кстати, не какой-нибудь дедовский пузырёк, а **pdqsort** — этакая помесь быстрой сортировки, пирамидальной и вставками. Штука охуенно быстрая в большинстве случаев, так что не парься.
А теперь, как этим богатством пользоваться? Есть два основных подхода, выбирай по настроению.
**1. Классика жанра: реализуем интерфейс.**
Это когда ты делаешь из своего слайса отдельный тип и навешиваешь на него методы. Подходит, если ты планируешь сортировать этот тип чаще, чем материться.
```go
_type User struct {
Name string
Age int
}
// ByAge — это наш кастомный тип для сортировки юзеров по возрасту.
_type ByAge []User
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func main() {
users := []User{
{"Alice", 25},
{"Bob", 20},
}
sort.Sort(ByAge(users)) // Превращаем в ByAge и сортируем.
fmt.Println(users) // [{Bob 20} {Alice 25}] — Боб теперь первый, потому что молодой ещё.
}
_```
**2. Современный и ленивый способ: `sort.Slice`.**
Появился в Go 1.8 и спас тысячи программистов от писанины лишних типов. Просто берёшь слайс и даёшь функцию, которая говорит, какой элемент меньше. Всё, ебушки-воробушки!
```go
_func main() {
users := []User{
{"Alice", 25},
{"Bob", 20},
}
// Хочешь по имени? Без проблем!
sort.Slice(users, func(i, j int) bool {
return users[i].Name < users[j].Name
})
fmt.Println(users) // [{Alice 25} {Bob 20}] — Алиса первая, ибо "A" раньше "B".
}
_```
Ну и для совсем простых случаев, чтобы мозг не выебывался, есть готовые функции: `sort.Ints()`, `sort.Float64s()`, `sort.Strings()`. Кидаешь туда свой слайс примитивов — получаешь отсортированный. Красота, ёпта!
Вот и вся магия. Никаких костылей, всё идиоматично и быстро. Главное — не перепутай `Less`, а то отсортируешь наоборот, и потом будешь думать, что же пошло не так.