Еще один распространенный вариант использования циклов на массивах — агрегация, которую мы рассмотрим в этом уроке.
Как работает агрегация
Агрегацией считаются любые вычисления, которые строятся на основе всего набора данных — например, поиск максимального или среднего числа, подсчет суммы и так далее. Агрегирующие функции особенно популярны в работе с цифрами и таблицами в Google Sheets и Microsoft Excel.
Для начала рассмотрим такой код:
<?php
function calculateMax($coll)
{
// Если коллекция пустая, то у нее не может быть максимального значения
// В подобных ситуациях принято возвращать null
if (empty($coll)) {
return null;
}
// Сравнение элементов нужно начать с какого-то первого элемента
$max = $coll[0]; // Принимаем за максимальное число первый элемент
// Обход начинаем со второго элемента
for ($i = 1; $i < sizeof($coll); $i++) {
// Если текущий элемент больше максимального,
// то он становится максимальным
if ($coll[$i] > $max) {
$max = $coll[$i];
}
}
// Не забываем вернуть максимальное число
return $max;
}
print_r(calculateMax([]));
print_r(calculateMax([3, 2, -10, 38, 0]));
// => 38
https://repl.it/@hexlet/php-arrays-aggregation-max
Алгоритм поиска максимального числа в массиве выглядит так:
- Если массив пустой, то возвращаем
null
. Это классический пример использования идиомы guard expression (охраняющее выражение). Ее идея в том, что в начале функции проверяются самые простые условия, для которых нужен минимум вычислений. При таком подходе основной код находится на верхнем уровне, а не внутри условной конструкции. Такой код легче читать, потому что у него меньше вложенность. - Если массив не пустой, берем за точку отсчета первый элемент массива и считаем его максимальным.
- Обходим массив, начиная со второго элемента и сравниваем каждое значение с максимальным. Если текущий рассматриваемый элемент больше максимального, то он становится максимальным.
- После обхода возвращаем результат.
Главное, что нужно увидеть в этом коде — место определения переменной $max
. Новички часто забывают, что переменную нужно определить до ее использования. Объявленные внутри цикла переменные не должны использоваться за пределами цикла, поэтому переменная и определяется до его начала.
В большинстве языков переменные, определенные внутри блока кода, видны только внутри этого блока. Именно так работает тело цикла в нашем случае. Другими словами, область видимости таких переменных ограничивается блоком кода, то есть мы не можем получить доступ к ним вне блока.
Обратите внимание, что начальным значением $max
взят первый элемент, а не 0
или другое число. Так происходит, потому что все числа в массиве могут быть меньше нуля, и тогда мы получим неверный ответ.
Второй важный момент: мы делаем возврат только после обхода всего массива. Если бы return
был внутри цикла, то мы рассмотрели массив не полностью. Такая ошибка часто встречается у новичков.
Нейтральный элемент
Рассмотрим поиск суммы:
<?php
function calculateSum($coll)
{
// Начальное значение суммы
$sum = 0;
foreach ($coll as $num) {
// Поочередно складываем все элементы
$sum += $num;
}
return $sum;
}
// Сумма элементов всегда возвращает какое-то число
// Если массив пустой, то сумма его элементов равна нулю
print_r(calculateSum([]));
print_r("\n");
print_r(calculateSum([3, 2, -10, 38, 0]));
// => 0
// => 33
https://repl.it/@hexlet/php-arrays-aggregation-sum
Алгоритм поиска суммы значительно проще, но обладает парой важных нюансов.
Чему равна сумма элементов пустого массива? С точки зрения математики такая сумма равна нулю, что совпадает со здравым смыслом. Если у нас нет яблок, значит у нас есть ноль яблок. Функции в программировании работают по этой логике.
Второй момент связан с начальным элементом суммы. В коде используется 0
или так называемый «нейтральный элемент операции сложения на множестве вещественных чисел». Нейтральный элемент бинарной операции используется, но ничего не меняет. Например, сложение любого числа с нулем всегда дает это же число. На практике это значит, что мы можем прибавить ноль к любому выражению и получить ту же сумму:
3 + 2 + 8 = 0 + 3 + 2 + 8
Этим свойством мы и пользуемся в нашем коде. Нейтральный элемент – важная часть любой агрегирующей операции. Именно с него начинается сам процесс агрегации. В случае сложения – это 0, в случае умножения – 1.
Агрегация далеко не всегда означает, что коллекция элементов сводится к некоторому простому значению. Результатом агрегации может быть даже сложная структура — например, массив. Подобные примеры часто встречаются в реальной жизни. Самый простой пример – это список уникальных слов в тексте.
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.