← Назад к вопросам

Что такое compactMap?

2.0 Middle🔥 191 комментариев
#CI/CD и инструменты разработки#Soft Skills и карьера

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое compactMap?

compactMap — это метод высшего порядка (higher-order function) в Swift, который выполняет преобразование (map) коллекции (например, массива) и одновременно фильтрацию (filter), удаляя nil значения из результата. Он объединяет функциональность map и последующего удаления nil, предоставляя удобный и эффективный способ обработки данных.

Основная идея и отличие от map

  • map преобразует каждый элемент коллекции, используя предоставленное замыкание (closure), и возвращает массив того же размера, где некоторые элементы могут быть nil.
  • compactMap также преобразует элементы, но затем автоматически "уплотняет" (compact) результат, удаляя все nil значения. Это особенно полезно, когда преобразование может возвращать опциональные значения (Optional<T>).

Пример для сравнения

let strings = ["1", "2", "не число", "4"]

// Используем map с преобразованием в Int
let mappedResult = strings.map { Int($0) }
print(mappedResult) // [Optional(1), Optional(2), nil, Optional(4)]
// Результат содержит nil на третьей позиции

// Используем compactMap
let compactedResult = strings.compactMap { Int($0) }
print(compactedResult) // [1, 2, 4]
// nil удалён, результат содержит только не-опциональные Int

В примере выше compactMap не только преобразовал строки в Int?, но и отфильтровал неудачные преобразования, вернув массив [Int].

Синтаксис и использование

Метод доступен для последовательностей (Sequence) и коллекций (Collection). Его синтаксис аналогичен map:

let resultArray = originalArray.compactMap { element in
    // Возвращаем опциональное значение или nil
    return someTransformation(element)
}

Замыкание принимает элемент исходной коллекции и возвращает опциональное значение (Optional). Все nil исключаются из финального результата.

Типичные сценарии применения

  1. Преобразование с возможной неудачей Часто используется для преобразования данных, где некоторые входные значения могут быть некорректными.
let userInput = ["42", "100", "abc", "75"]
let validNumbers = userInput.compactMap { Int($0) }
// validNumbers = [42, 100, 75]
  1. Работа с опциональными свойствами объектов Например, извлечение конкретных свойств из массива объектов, где некоторые свойства могут отсутствовать.
struct Person {
    let name: String?
}

let people = [Person(name: "Alice"), Person(name: nil), Person(name: "Bob")]
let names = people.compactMap { $0.name }
print(names) // ["Alice", "Bob"]
  1. Фильтрация и трансформация в одну операцию Упрощает код, избегая раздельных вызовов map и filter.
// Без compactMap (два шага)
let numbers = ["1", "2", "three"]
let mapped = numbers.map { Int($0) } // [Int?]
let filtered = mapped.filter { $0 != nil } // [Int?]
let final = filtered.map { $0! } // [Int]

// С compactMap (один шаг)
let finalCompact = numbers.compactMap { Int($0) } // [Int]

compactMap vs flatMap

В Swift 4.1 и выше произошло разделение:

  • compactMap специализируется на удалении nil из последовательности опциональных значений.
  • flatMap теперь используется для "разворачивания" (flattening) вложенных последовательностей (например, преобразования массива массивов в один плоский массив).

Пример для flatMap:

let arrays = [[1, 2], [3, 4]]
let flattened = arrays.flatMap { $0 }
print(flattened) // [1, 2, 3, 4]

Производительность и внутренняя работа

compactMap оптимизирован и обычно выполняется за O(n), где n — количество элементов. Он не создает промежуточных массивов явно, что делает его эффективным по памяти. Однако важно помнить, что замыкание выполняется для каждого элемента, поэтому сложные операции внутри могут повлиять на производительность.

Практические советы

  • Используйте compactMap, когда логика естественно включает преобразование с возможным nil.
  • Для сложных преобразований, где требуется дополнительная фильтрация (не только по nil), иногда комбинация map и filter может быть более читаемой.
  • В Swift 5 и выше compactMap также доступен для опциональных последовательностей (например, String?), что расширяет его применение.

Ключевое преимущество compactMap — это сочетание безопасности и удобства: он исключает необходимость ручной обработки nil и принудительного разворачивания (!) опционалов, снижая риск ошибок времени выполнения.

В заключение, compactMap — это мощный инструмент функционального программирования в Swift, который помогает писать более чистый, безопасный и выразительный код при работе с преобразованиями коллекций, где возможны неудачи.