0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Последняя функция, которую нам осталось рассмотреть из большой тройки функций высшего порядка - это reduce. Эта функция более мощная, чем map и filter, и в конечном итоге они могут быть выражены через reduce. По сути эта функция является базовой. Она очень мощная и позволяет решать большинство возникающих задач при работе по преобразованию структур.</p>
1
<p>Последняя функция, которую нам осталось рассмотреть из большой тройки функций высшего порядка - это reduce. Эта функция более мощная, чем map и filter, и в конечном итоге они могут быть выражены через reduce. По сути эта функция является базовой. Она очень мощная и позволяет решать большинство возникающих задач при работе по преобразованию структур.</p>
2
<h2>Количество заголовков</h2>
2
<h2>Количество заголовков</h2>
3
<p>В этом примере решается задача подсчёта количества заголовков. Вообще говоря, можно считать количество всего, чего угодно. Но в данном случае, это может быть полезно вот для чего.</p>
3
<p>В этом примере решается задача подсчёта количества заголовков. Вообще говоря, можно считать количество всего, чего угодно. Но в данном случае, это может быть полезно вот для чего.</p>
4
<p>Мы уже говорили, что в HTML заголовок h1 на странице может быть только один. Представьте, что мы строим валидатор, который проверяет наш HTML на качество и соответствие стандартам. Одной из проверок будет проверка на количество заголовков первого уровня. Если их больше одного, мы можем выдать предупреждение, что так делать нельзя.</p>
4
<p>Мы уже говорили, что в HTML заголовок h1 на странице может быть только один. Представьте, что мы строим валидатор, который проверяет наш HTML на качество и соответствие стандартам. Одной из проверок будет проверка на количество заголовков первого уровня. Если их больше одного, мы можем выдать предупреждение, что так делать нельзя.</p>
5
<p>В примере видно, что мы собираем HTML, в котором два заголовка h1. Мы применяем функцию headersCount, которая первым параметром принимает имя тега (можно было оставить только номер заголовка) и, собственно, HTML. В итоге в данной ситуации она выдаст значение 2.</p>
5
<p>В примере видно, что мы собираем HTML, в котором два заголовка h1. Мы применяем функцию headersCount, которая первым параметром принимает имя тега (можно было оставить только номер заголовка) и, собственно, HTML. В итоге в данной ситуации она выдаст значение 2.</p>
6
<p>Внутри функция устроена так:</p>
6
<p>Внутри функция устроена так:</p>
7
<p>Поскольку она выдаёт какой-то конечный результат (скалярный), то понятно, что это другой тип преобразования. В отличие от map и filter нам нужно делать так называемую свёртку, когда все элементы перебираются, происходит общее вычисление, и в конце мы получаем новый результат, который не является отображением или фильтрацией предыдущего списка. Эту задачу можно решить с помощью итеративного процесса, используя внутреннюю функцию $iter или цикл. Итак, давайте посмотрим, что здесь происходит.</p>
7
<p>Поскольку она выдаёт какой-то конечный результат (скалярный), то понятно, что это другой тип преобразования. В отличие от map и filter нам нужно делать так называемую свёртку, когда все элементы перебираются, происходит общее вычисление, и в конце мы получаем новый результат, который не является отображением или фильтрацией предыдущего списка. Эту задачу можно решить с помощью итеративного процесса, используя внутреннюю функцию $iter или цикл. Итак, давайте посмотрим, что здесь происходит.</p>
8
<p>Как обычно, при итеративном процессе мы вызываем $iter($elements, 0) и передаём туда аккумулятор и наши элементы. Начальное значение аккумулятора равно 0, потому что наша функция считает количество.</p>
8
<p>Как обычно, при итеративном процессе мы вызываем $iter($elements, 0) и передаём туда аккумулятор и наши элементы. Начальное значение аккумулятора равно 0, потому что наша функция считает количество.</p>
9
<p>Дальше внутри функции $iter всё происходит, как обычно. Мы берем "голову", вычисляем новый аккумулятор. Здесь есть проверка is: соответствует ли переданное имя тега текущему элементу (в нашем случае, это заголовки). И если это так, то аккумулятор обновляется $acc + 1. Если текущий элемент не является заголовком, то $newAcc становится равным $acc, т.е. не происходит никаких изменений.</p>
9
<p>Дальше внутри функции $iter всё происходит, как обычно. Мы берем "голову", вычисляем новый аккумулятор. Здесь есть проверка is: соответствует ли переданное имя тега текущему элементу (в нашем случае, это заголовки). И если это так, то аккумулятор обновляется $acc + 1. Если текущий элемент не является заголовком, то $newAcc становится равным $acc, т.е. не происходит никаких изменений.</p>
10
<p>После этого мы рекурсивно вызываем функцию $iter, передавая в неё "хвост" - tail($items) (остаток наших элементов) и новый аккумулятор. Таким образом итерация за итерацией аккумулятор накапливается и в самом конце, когда $items окажется пустым, то наружу вернётся значение нашего аккумулятора.</p>
10
<p>После этого мы рекурсивно вызываем функцию $iter, передавая в неё "хвост" - tail($items) (остаток наших элементов) и новый аккумулятор. Таким образом итерация за итерацией аккумулятор накапливается и в самом конце, когда $items окажется пустым, то наружу вернётся значение нашего аккумулятора.</p>
11
<h2>Свёртка</h2>
11
<h2>Свёртка</h2>
12
<p>Как видно данная операция может быть обобщена. Причём в этом случае обобщение может быть гораздо сильнее, чем отображение или фильтрация списков, потому что в данном случае reduce может сгенерировать даже новый список, который может фактически быть отражением предыдущего списка, но при этом он может быть и не отражением: быть другим по размерам, содержать совершенно другие данные. Т.е. reduce позволяет нам создавать за счёт аккумулятора нечто новое на основе базового списка.</p>
12
<p>Как видно данная операция может быть обобщена. Причём в этом случае обобщение может быть гораздо сильнее, чем отображение или фильтрация списков, потому что в данном случае reduce может сгенерировать даже новый список, который может фактически быть отражением предыдущего списка, но при этом он может быть и не отражением: быть другим по размерам, содержать совершенно другие данные. Т.е. reduce позволяет нам создавать за счёт аккумулятора нечто новое на основе базового списка.</p>
13
<h3>Особенности</h3>
13
<h3>Особенности</h3>
14
<ul><li>Reduce может заменить map/filter.</li>
14
<ul><li>Reduce может заменить map/filter.</li>
15
<li>Обычно последняя функция в цепочке преобразований.</li>
15
<li>Обычно последняя функция в цепочке преобразований.</li>
16
<li>Её часто называют fold.</li>
16
<li>Её часто называют fold.</li>
17
<li>Внутренняя реализация возможна только через итеративный процесс.</li>
17
<li>Внутренняя реализация возможна только через итеративный процесс.</li>
18
</ul><p>reduce может заменить map/filter, но придётся делать reverse, чтобы элементы были возвращены в правильном порядке.</p>
18
</ul><p>reduce может заменить map/filter, но придётся делать reverse, чтобы элементы были возвращены в правильном порядке.</p>
19
<p>reduce обычно последняя функция в цепочке преобразований. После map и filter в конечном итоге может применятся reduce для получения какого-то результата. Это не всегда так, но чаще всего.</p>
19
<p>reduce обычно последняя функция в цепочке преобразований. После map и filter в конечном итоге может применятся reduce для получения какого-то результата. Это не всегда так, но чаще всего.</p>
20
<p>reduce часто называют<em>fold</em>в зависимости от языка. В некоторых языках встречаются и другие названия. Например, в Ruby - это inject.</p>
20
<p>reduce часто называют<em>fold</em>в зависимости от языка. В некоторых языках встречаются и другие названия. Например, в Ruby - это inject.</p>
21
<p>Внутренняя реализация возможна только через итеративный процесс, потому что сам reduce реализует его из-за того, что явно используется аккумулятор.</p>
21
<p>Внутренняя реализация возможна только через итеративный процесс, потому что сам reduce реализует его из-за того, что явно используется аккумулятор.</p>
22
<h2>Количество заголовков</h2>
22
<h2>Количество заголовков</h2>
23
<p>Давайте теперь рассмотрим использование редьюса как концепции и отдельной функции. Мы, как обычно, создаём HTML и дальше вызываем reduce, который принимает на вход уже три элемента. Это сильно отличается от map или filter. Первый аргумент - это сами элементы, которые мы будем обрабатывать, второй - функция. Третьим параметром мы передаём аккумулятор. Он сильно зависит от того, какую операцию мы собираемся делать. Если бы нам понадобилось сформировать список, то начальным значением был бы пустой список.</p>
23
<p>Давайте теперь рассмотрим использование редьюса как концепции и отдельной функции. Мы, как обычно, создаём HTML и дальше вызываем reduce, который принимает на вход уже три элемента. Это сильно отличается от map или filter. Первый аргумент - это сами элементы, которые мы будем обрабатывать, второй - функция. Третьим параметром мы передаём аккумулятор. Он сильно зависит от того, какую операцию мы собираемся делать. Если бы нам понадобилось сформировать список, то начальным значением был бы пустой список.</p>
24
<p>Та функция, которая непосредственно делает всю обработку в отличие от фильтра и мапа принимает на вход два параметра. Первый - это текущий элемент, с которым мы работаем, а второй - это аккумулятор, потому что только мы знаем, как хотим его изменять. Всё, что делает внутренняя реализация переданной функции: мы проверяем, является ли текущий элемент заголовком h1, и если да, то возвращаем аккумулятор, увеличенный на единицу, если нет, то возвращается сам аккумулятор.</p>
24
<p>Та функция, которая непосредственно делает всю обработку в отличие от фильтра и мапа принимает на вход два параметра. Первый - это текущий элемент, с которым мы работаем, а второй - это аккумулятор, потому что только мы знаем, как хотим его изменять. Всё, что делает внутренняя реализация переданной функции: мы проверяем, является ли текущий элемент заголовком h1, и если да, то возвращаем аккумулятор, увеличенный на единицу, если нет, то возвращается сам аккумулятор.</p>
25
<p>В конечном итоге эта функция считает нам количество заголовков.</p>
25
<p>В конечном итоге эта функция считает нам количество заголовков.</p>
26
<p>Ниже еще пример использования reduce при работе со списками:</p>
26
<p>Ниже еще пример использования reduce при работе со списками:</p>
27
27