Как отсортировать массив кастомных объектов по значению свойства в 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 элементов разница между подходами незаметна. Выбирайте тот, который делает код читаемее.
Ответов пока нет.
Войдите чтобы оставить ответ