PHP: Функции
Теория: Агрегация
Последняя функция из нашей тройки — array_reduce или свертка. В других языках она называется accumulate или fold. Эта функция используется для агрегации. Она устроена немного сложнее, чем map и filter, но сохраняет общий подход с передачей функции.
Как обычно, начнем с примера на циклах. Реализуем код, находящий самого взрослого пользователя:
Основное отличие агрегации от отображения и фильтрации заключается в том, что результатом агрегации может быть любой тип данных — как примитивный, так и составной. Например, результатом может быть массив. Кроме того, агрегация нередко подразумевает инициализацию начальным значением. В примере выше она выполняется на строчке $oldest = $users[0];.
Посмотрим еще один пример агрегации — группировку имен пользователей по возрасту:
В этом примере результатом агрегации становится массив массивов, который в самом начале инициируется пустым массивом. Значение, которое накапливает результат агрегации, принято называть словом аккумулятор. В примерах выше это $oldest и $usersByAge.
Реализуем первый пример, используя array_reduce:
Функция array_reduce принимает на вход три параметра. Два из них уже традиционны — это коллекция и функция-обработчик, а вот третьим выступает начальное значение аккумулятора. Поиск самого взрослого пользователя аналогичен поиску максимального или минимального числа в массиве. Соответственно, аккумулятор должен быть инициализирован первым пользователем. Этот же аккумулятор возвращается наружу.
Колбэк-функция, передаваемая в array_reduce — это самая важная часть и ключ к пониманию работы всего механизма агрегации. Она принимает на вход два значения:
- Текущее значение аккумулятора
- Текущий обрабатываемый элемент
Задача функции — вернуть новое значение аккумулятора. При этом array_reduce никак не анализирует содержимое аккумулятора. Все, что она делает — она передает значение аккумулятора в каждый новый вызов, пока не будет обработана вся коллекция, и в конце концов вернет его наружу. Подчеркнем, что возвращать аккумулятор надо всегда, даже если он не изменился.
Второй пример с использованием array_reduce выглядит так:
Код практически не изменился. Как видите, ушел цикл и появился возврат аккумулятора из анонимной функции.
Перейдем к реализации:
Функция array_reduce очень мощная. Формально, можно работать, используя только ее, потому что она может заменить отображение и фильтрацию. Но делать так не стоит. Агрегация управляет состоянием (аккумулятором) явно. Такой код всегда сложнее и требует больше действий. Поэтому, если задачу возможно решить отображением или фильтрацией, то так и нужно делать.
.png)
