Какие функции высшего порядка для работы с коллекциями вы знаете в Swift?

«Какие функции высшего порядка для работы с коллекциями вы знаете в Swift?» — вопрос из категории Swift Core, который задают на 23% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Функции высшего порядка — это функции, которые принимают другие функции в качестве аргументов или возвращают их. В Swift для коллекций (Array, Set, Dictionary) наиболее часто используются следующие:

Основные функции

  1. map(_:)[T]

    • Назначение: Преобразует каждый элемент коллекции, применяя к нему переданное замыкание.
    • Сложность: O(n).
    • Пример:
      let numbers = [1, 2, 3]
      let squared = numbers.map { $0 * $0 } // [1, 4, 9]
      let strings = numbers.map { "Number ($0)" } // ["Number 1", "Number 2", "Number 3"]
  2. filter(_:)[T]

    • Назначение: Возвращает новую коллекцию, содержащую только те элементы, для которых переданное замыкание возвращает true.
    • Сложность: O(n).
    • Пример:
      let numbers = [1, 2, 3, 4, 5]
      let evens = numbers.filter { $0 % 2 == 0 } // [2, 4]
  3. reduce(into:_:)Result

    • Назначение: Объединяет все элементы коллекции в одно результирующее значение, используя начальное значение и замыкание для объединения.
    • Сложность: O(n).
    • Примеры:

      let numbers = [1, 2, 3, 4]
      let sum = numbers.reduce(0, +) // 10 (0 + 1 + 2 + 3 + 4)
      let product = numbers.reduce(1, *) // 24 (1 * 1 * 2 * 3 * 4)
      
      // Более сложный пример: группировка слов по первой букве
      let words = ["apple", "banana", "apricot", "blueberry"]
      let grouped = words.reduce(into: [:]) { result, word in
          result[word.first!, default: []].append(word)
      }
      // grouped = ["a": ["apple", "apricot"], "b": ["banana", "blueberry"]]
  4. compactMap(_:)[T]

    • Назначение: Выполняет преобразование (map) и затем удаляет все nil значения из результата.
    • Сложность: O(n).
    • Пример:
      let strings = ["1", "2", "three", "4"]
      let numbers = strings.compactMap { Int($0) } // [1, 2, 4]
      // Эквивалентно: strings.map { Int($0) }.filter { $0 != nil }.map { $0! }
  5. flatMap(_:)[T]

    • Назначение: «Разворачивает» вложенные коллекции (например, массив массивов) в один плоский массив. В современных версиях Swift для этой цели используется joined().
    • Сложность: O(n + m).
    • Пример:
      let nestedArray = [[1, 2], [3, 4, 5]]
      let flatArray = nestedArray.flatMap { $0 } // [1, 2, 3, 4, 5]
      // Альтернатива:
      let flatArray2 = Array(nestedArray.joined()) // [1, 2, 3, 4, 5]
  6. forEach(_:)Void

    • Назначение: Выполняет переданное замыкание для каждого элемента коллекции. Не возвращает новый массив.
    • Отличие от for-in: В forEach нельзя использовать break или continue. Используется для side-эффектов.
    • Пример:
      ["a", "b", "c"].forEach { print($0) }
      // Вывод:
      // a
      // b
      // c
  7. sorted(by:)[T]

    • Назначение: Возвращает новый отсортированный массив на основе переданного критерия сравнения.
    • Сложность: O(n log n).
    • Пример:
      let numbers = [3, 1, 4, 2]
      let ascending = numbers.sorted() // [1, 2, 3, 4] (по умолчанию)
      let descending = numbers.sorted(by: >) // [4, 3, 2, 1]

Цепочки вызовов (Chaining)

Сила этих функций раскрывается в комбинации:

let result = (1...10)
    .filter { $0 % 2 == 0 }       // [2, 4, 6, 8, 10]
    .map { $0 * $0 }              // [4, 16, 36, 64, 100]
    .reduce(0, +)                 // 220
print(result) // 220

Этот код находит сумму квадратов всех четных чисел от 1 до 10, демонстрируя декларативный и выразительный стиль программирования.