В Swift мы можем использовать функции reduce() и filter() для преобразований коллекций без использования циклов.
Функция reduce() превращает коллекцию в одно значение. Функция filter() возвращает значения, если необходимое условие истинно.
Вы можете использовать эти функции для массивов, словарей, множество, диапазонов и любых других типов данных, которые можно перебирать.
Функция reduce
Функция reduce(_:_:) перебирает каждый элемент в коллекции и сводит их к одному значению. Воспринимайте ее как способ объединить несколько значений в одно.
Каким образом вы можете перейти от множества значений в коллекции к одному значению? Вот несколько примеров:
- Подсчет суммы нескольких значений: 3 + 4 + 5 = 12.
- Конкатенация коллекции строк: [“Дом”, “Комната”, “Стул”] = “Дом, Комната, Стул”.
- Усреднение набора значений: (7 + 3 + 10) / 3 = 7/3 + 3/3 + 10/3 = 6.667
Вы можете решить любую из этих проблем с помощью цикла for, но с помощью функции reduce(_:_:) ваш код будет гораздо проще и компактней.
let values = [3, 4, 5] let sum = values.reduce(0, +) print(sum) // 12
Функция принимает два аргумента – начальное значение и замыкание. В приведенном выше коде мы используем оператор +.
Вы также можете написать свое собственное замыкание:
let values = [7.0, 3.0, 10.0] let average = values.reduce(0.0) { $0 + $1 } / Double(values.count) print(average) // 6.666666666666667
В приведенном выше примере мы рассчитываем среднее из трех чисел. Все значения имеют тип Double. Сначала мы складываем все числа, а затем делим их на общее количество.
Функция reduce(_:_:) имеет свои особенности:
- Функция принимает два параметра: начальное значение и замыкание.
- Замыкание также принимает два параметра: текущий результат и новое значение.
let values = [7, 3, 10] let sum = values.reduce(0) { print("\($0) + \($1) = \($0 + $1)") return $0 + $1 } print(sum) // 0 + 7 = 7 // 7 + 3 = 10 // 10 + 10 = 20 // 20
В приведенном примере вы можете четко видеть 2 параметра замыкания – $0 и $1.
Мы начинаем с 0, потом добавляем 7. На следующем шаге мы берем 7 – текущее значение – и добавляем 3 – следующее значение.
Функция filter
Функция filter() перебирает каждый элемент в коллекции и возвращает новую коллекцию, которая содержит только те элементы, которые удовлетворяют поставленным условиям. Это все равно, что применять if условие к коллекции и сохранять только те значения, которые проходят проверку.
let values = [11, 13, 14, 6, 17, 21, 33, 22] let even = values.filter { $0.isMultiple(of: 2) } print(even) // [14, 6, 22]
В приведенном примере мы фильтрум четные числа из массива values. Функция isMultiple(of:) возвращает true, когда текущее значение можно разделить на 2. В противном случае возвращается false.
В отличие от функций map(_:) и reduce(_:_:) функция filter(_:) должна возвратить либо true либо false. Когда замыкание возвращает true, значения сохраняются, а когда возвращается false, значения опускаются.
Мы можем расписать данное замыкание более подробно:
let values = [11, 13, 14, 17, 21, 33, 22] let even = values.filter({ (value: Int) -> Bool in return value.isMultiple(of: 2) }) print(even) // [11, 13, 17, 21, 33]
Группировка нескольких функций
Вы также можете объединять несколько функций высшего порядка.
Допустим, у нас есть класс студентов. Вы знаете год, когда родился каждый студент. Вы хотите рассчитать совокупный возраст всех учащихся, родившихся в 2000 году или позже.
let now = 2020 let years = [1989, 1992, 2003, 1970, 2014, 2001, 2015, 1990, 2000, 1999] let sum = years.filter({ $0 >= 2000 }).map({ now - $0 }).reduce(0, +) print(sum) // 67
В приведенном выше примере кода используется связывание нескольких функций. Данный код использует результат одной функции в качестве входных данных для другой.