Как отсортировать массив кастомных объектов по значению свойства в Swift?
Основные способы сортировки кастомных объектов в Swift
В Swift есть несколько подходов для сортировки массивов с пользовательскими типами. Рассмотрим самые популярные и эффективные.
1. Использование замыкания (Closure) с sorted(by:)
Самый простой и гибкий способ — передать замыкание, которое сравнивает два элемента:
// Сортировка по возрасту (по возрастанию)
let sortedByAge = users.sorted { $0.age < $1.age }
// Сортировка по имени (в алфавитном порядке)
let sortedByName = users.sorted { $0.name < $1.name }
// Сортировка по убыванию счета
let sortedByScoreDesc = users.sorted { $0.score > $1.score }
Если нужно отсортировать исходный массив (изменяемый), используйте sort(by:):
var mutableUsers = users
mutableUsers.sort { $0.age < $1.age }
2. Множественная сортировка (по нескольким свойствам)
Когда нужно отсортировать сначала по одному полю, а при равенстве — по другому:
// Сначала по возрасту, затем по имени (если возраст одинаковый)
let sortedMulti = users.sorted {
if $0.age != $1.age {
return $0.age < $1.age
} else {
return $0.name < $1.name
}
}
Более лаконичный вариант с кортежами:
let sortedMultiTuple = users.sorted {
($0.age, $0.name) < ($1.age, $1.name)
}
3. Реализация протокола Comparable
Если вы часто сортируете объекты одного типа, можно сделать тип сравниваемым:
struct User: Comparable {
let name: String
let age: Int
let score: Double
static func < (lhs: User, rhs: User) -> Bool {
// Определяем логику сравнения
return lhs.age < rhs.age
}
static func == (lhs: User, rhs: User) -> Bool {
return lhs.age == rhs.age && lhs.name == rhs.name
}
}
// Теперь можно использовать просто sorted()
let sortedUsers = users.sorted()
4. Использование NSSortDescriptor (для Obj-C совместимости)
Если вы работаете с NSArray или Core Data, можно использовать классический подход:
import Foundation
let ageDescriptor = NSSortDescriptor(key: "age", ascending: true)
let nameDescriptor = NSSortDescriptor(key: "name", ascending: true)
let sortedNSArray = (users as NSArray).sortedArray(using: [ageDescriptor, nameDescriptor])
Важные моменты
- sorted() возвращает новый отсортированный массив, не изменяя исходный.
- sort() изменяет исходный массив (должен быть var).
- Для обратной сортировки используйте оператор > или вызовите
.reversed(). - Сортировка по строкам по умолчанию чувствительна к регистру. Для case-insensitive используйте
$0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending.
Рекомендую начинать с замыканий — это самый гибкий и понятный способ. Переходите к протоколу Comparable, когда один тип сортируется одинаково в разных местах кода.
<<Альтернативный подход: сортировка через map и словари
Иногда удобно сгруппировать данные перед сортировкой. Например, если нужно отсортировать по категориям:
// Группировка по возрасту
let groupedByAge = Dictionary(grouping: users) { $0.age }
// Сортировка ключей
let sortedKeys = groupedByAge.keys.sorted()
// Восстановление массива
let sortedGrouped = sortedKeys.flatMap { groupedByAge[$0]! }
Сортировка с учетом локали
Для русских имён и текста важно использовать локализованное сравнение:
let sortedLocalized = users.sorted {
$0.name.localizedStandardCompare($1.name) == .orderedAscending
}
Этот метод корректно обрабатывает букву "ё", регистр и диакритические знаки. Для большинства реальных приложений с пользовательским интерфейсом стоит использовать именно его, а не просто < для строк.
Производительность
Все методы сортировки в Swift используют алгоритм Timsort (гибрид сортировки слиянием и вставками) со сложностью O(n log n). Для массивов до 10 000 элементов разница между подходами незаметна. Выбирайте тот, который делает код читаемее.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Как вычислить факториал числа в Python?