> Что должна возвращать функция сравнения (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 - писать замыкание вручную.

При сортировке словарей или объектов с несколькими полями сравнивайте по приоритету: сначала главный ключ, затем вторичный. Например, сортировка пользователей по возрасту, затем по имени.

Пример кода

SWIFT
struct User {
let name: String
let 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 in
if 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 полей - аккуратно с nil
let optionalUsers: [User?] = [nil, users[0], users[1]]
let sortedOptional = optionalUsers.sorted { lhs, rhs in
switch (lhs, rhs) {
case (nil, nil): return false
case (nil, _): return false // nil идут в конец
case (_, nil): return true
case let (l?, r?): return l.age < r.age
}
}

Как отвечать на собеседовании

Начните с точного определения: Bool, означающий "первый меньше второго". Затем перечислите три свойства строгого слабого порядка - асимметричность, транзитивность, отсутствие рефлексивности. Приведите пример с несколькими полями и упомяните, что для равных элементов возвращается false в обе стороны. Если спросят про производительность - отметьте, что некорректная функция сравнения может привести к O(n²) или бесконечному циклу в худшем случае. Для senior-уровня добавьте про Comparator в Objective-C и про то, что Swift-замыкания захватывают контекст.

Что проверяет интервьюер

  • Понимание контракта функции сравнения, а не просто синтаксиса.
  • Знание edge cases: равные элементы, опциональные значения, множественные ключи.
  • Умение объяснить, почему нарушение транзитивности - это баг, а не просто "медленная сортировка".
  • Способность выбрать правильный инструмент: sorted(by:) vs sort(by:), tuple comparison vs ручное сравнение.
  • Для senior - осознание связи с Comparable протоколом и generic-алгоритмами.

Типичные ошибки

  • Возврат true для равных элементов - ломает асимметричность, сортировка может "переставлять" равные объекты бесконечно.
  • Использование <= вместо < - то же самое нарушение.
  • Сравнение только по одному полю, когда нужно по нескольким - результат нестабилен.
  • Забывают про nil в опционалах: lhs < rhs не компилируется для Int? без распаковки.
  • Путают порядок аргументов: return rhs < lhs инвертирует сортировку, но не всегда очевидно.
  • В Objective-C-блоках возвращают NSComparisonResult вместо Bool - это другой API, но та же логика.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью