> Что должна возвращать функция сравнения (iOS, Swift)
Уровень: senior · Роль: mobile · Категория: Технические вопросы
Компании: Revolut
Стек: iOS, Swift
> Пример ответа
Короткий ответ
Функция сравнения в Swift (например, для sort(by:) или sorted(by:)) должна возвращать Bool: true, если первый аргумент должен идти перед вторым в отсортированном порядке, и false в противном случае. Это строгий порядок (strict weak ordering): для равных элементов возвращается false в обе стороны, чтобы избежать неопределённого поведения и лишних перестановок.
Подробное объяснение
Функция сравнения - это замыкание вида (Element, Element) -> Bool. Она определяет отношение "меньше" (less-than) для элементов коллекции. Ключевые требования:
- Асимметричность: если
compare(a, b) == true, тоcompare(b, a)должно бытьfalse. Иначе алгоритм сортировки может зациклиться или дать некорректный результат. - Транзитивность: если
compare(a, b) == trueиcompare(b, c) == true, тоcompare(a, c)должно бытьtrue. Нарушение транзитивности ломает инварианты сортировки. - Рефлексивность запрещена:
compare(a, a)всегдаfalse. Для равных объектов возвращаемfalseв обе стороны - это сигнализирует об их эквивалентности.
В Swift стандартная сортировка (Introsort) опирается на эти свойства. Если функция сравнения не является строгим слабым порядком, результат не определён: массив может быть отсортирован непредсказуемо, вплоть до краха (в debug-режиме с санитайзерами).
Для опциональных значений или сложных структур используйте явную проверку: например, if let a = a, let b = b { return a < b } else { return a == nil } - но это уже про конкретные кейсы.
На практике
В iOS-разработке функция сравнения чаще всего используется в:
array.sorted(by:)- возвращает новый массив.array.sort(by:)- сортирует на месте.NSArray.sortedArray(comparator:)- для Objective-C-совместимости.- Кастомные
ComparatorдляNSSortDescriptor(Core Data, UITableView).
Важно помнить: для Comparable типов (Int, String, Date) можно использовать оператор < напрямую: array.sorted(by: <). Для структур без Comparable - писать замыкание вручную.
При сортировке словарей или объектов с несколькими полями сравнивайте по приоритету: сначала главный ключ, затем вторичный. Например, сортировка пользователей по возрасту, затем по имени.
Пример кода
SWIFTstruct User {let name: Stringlet age: Int}let users = [User(name: "Anna", age: 30),User(name: "Bob", age: 25),User(name: "Alice", age: 30)]// Сортировка по возрасту, затем по имениlet sorted = users.sorted { lhs, rhs inif lhs.age != rhs.age {return lhs.age < rhs.age}return lhs.name < rhs.name}// Эквивалентно с использованием tuple comparison (Swift 2.2+)let sortedTuple = users.sorted { ($0.age, $0.name) < ($1.age, $1.name) }// Для Optional полей - аккуратно с nillet optionalUsers: [User?] = [nil, users[0], users[1]]let sortedOptional = optionalUsers.sorted { lhs, rhs inswitch (lhs, rhs) {case (nil, nil): return falsecase (nil, _): return false // nil идут в конецcase (_, nil): return truecase let (l?, r?): return l.age < r.age}}
Как отвечать на собеседовании
Начните с точного определения: Bool, означающий "первый меньше второго". Затем перечислите три свойства строгого слабого порядка - асимметричность, транзитивность, отсутствие рефлексивности. Приведите пример с несколькими полями и упомяните, что для равных элементов возвращается false в обе стороны. Если спросят про производительность - отметьте, что некорректная функция сравнения может привести к O(n²) или бесконечному циклу в худшем случае. Для senior-уровня добавьте про Comparator в Objective-C и про то, что Swift-замыкания захватывают контекст.
Что проверяет интервьюер
- Понимание контракта функции сравнения, а не просто синтаксиса.
- Знание edge cases: равные элементы, опциональные значения, множественные ключи.
- Умение объяснить, почему нарушение транзитивности - это баг, а не просто "медленная сортировка".
- Способность выбрать правильный инструмент:
sorted(by:)vssort(by:), tuple comparison vs ручное сравнение. - Для senior - осознание связи с
Comparableпротоколом и generic-алгоритмами.
Типичные ошибки
- Возврат
trueдля равных элементов - ломает асимметричность, сортировка может "переставлять" равные объекты бесконечно. - Использование
<=вместо<- то же самое нарушение. - Сравнение только по одному полю, когда нужно по нескольким - результат нестабилен.
- Забывают про
nilв опционалах:lhs < rhsне компилируется дляInt?без распаковки. - Путают порядок аргументов:
return rhs < lhsинвертирует сортировку, но не всегда очевидно. - В Objective-C-блоках возвращают
NSComparisonResultвместоBool- это другой API, но та же логика.
> Похожие задачи по mobile
Все ли нормально с рекурсивно ссылающейся на себя структурой
Как реализовать потокобезопасный словарь
Что такое capture list в closure и как с ним работать
Какие типы данных относятся к стеку, а какие к куче
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью