Зарегистрируйтесь, чтобы продолжить обучение

Фильтрация списков PHP: Последовательности

Следующая операция после отображения списков, такая же по важности операция — это фильтрация. Они часто используются вместе. Давайте её разберём.

Самый простой пример в нашей библиотеке — это удаление элемента, например, заголовков.

<?php

use function Php\Html\Tags\HtmlTags\make;
use function Php\Html\Tags\HtmlTags\append;
use function Php\Html\Tags\HtmlTags\node;

$html1 = append(make(), node('h2', 'header1'));
$html2 = append($html1, node('h2', 'header2'));
$html3 = append($html2, node('p', 'content'));

$processedHtml = removeHeaders($html3);

Здесь создаётся HTML, в который добавляются ноды двух типов: заголовок и параграф. И после этого применяется функция removeHeaders. В свою очередь она возвращает новый HTML. И если мы его распечатаем, то увидим, что остался только параграф и больше ничего:

<?php

toString($processedHtml); // <p>content</p>

Удаление тегов

<?php

use function Php\Pairs\Data\Lists\l;
use function Php\Pairs\Data\Lists\isEmpty;
use function Php\Pairs\Data\Lists\is;
use function Php\Pairs\Data\Lists\head;
use function Php\Pairs\Data\Lists\tail;
use function Php\Pairs\Data\Lists\cons;

function removeHeaders($elements)
{
    if (isEmpty($elements)) {
        return l();
    } 

    $element = head($elements);
    $tailElements = tail($elements);
    if (is('h2', $element)) {
        return removeHeaders($tailElements);
    }

    return cons($element, removeHeaders($tailElements));
}

Давайте посмотрим, как устроена внутри эта функция. Она работает практически так же, как и map, за единственным исключением. Мы внутри проверяем, является ли элемент тегом, в данном случае заголовком. Если он является заголовком, то мы рекурсивно вызываем функцию removeHeaders с "хвостом" нашего списка $tailElements. Если нет, то мы вызываем cons и добавляем текущий элемент и рекурсивный вызов "хвоста". Если наш элемент является заголовком, то мы не делаем cons и просто пропускаем его. В конечном итоге нам вернётся список с отфильтрованными значениями.

Фильтрация

Фильтрация

Эта операция называется filter, также называется функция, которая её выполняет. Иногда её называют и по-другому, но чаще всего именно так. Как видно из картинки, filter не делает никаких преобразований. Задача этой функции исключительно — оставить только то, что нужно.

<?php

use function Php\Html\Tags\HtmlTags\make;
use function Php\Html\Tags\HtmlTags\append;
use function Php\Html\Tags\HtmlTags\node;
use function Php\Html\Tags\HtmlTags\filter;

$html1 = append(make(), node('h2', 'header1'));
$html2 = append($html1, node('h2', 'header2'));
$html3 = append($html2, node('p', 'content'));

$processedHtml = filter($html3, fn($element) => !is('h2', $element));

toString($processedHtml); //<p>content</p>

Посмотрим реализацию, используя функцию высшего порядка filter, которая производит изменения. Здесь тот же самый пример. Единственное отличие — мы вызываем не removeHeaders, а функцию filter. На вход передаётся 2 параметра: HTML и функция. Это стандарт для подобного вида функций. При этом функция, которую мы передаём, называется предикат, потому что она возвращает значение истина или ложь в зависимости от того, нужно ли сохранять элемент. Если она возвращает true, то элемент остаётся в списке, если false, то его не будет в новом списке.

Часто эта функция достаточно простая. Наш случай не исключение. Функция делает простую проверку, является ли элемент заголовком второго уровня. И если он этим заголовком не является, то всё хорошо и элемент остаётся в списке. Если мы распечатаем $processedHtml, то будет выведен ожидаемый список с одним элементом — тегом p.

Ниже еще несколько примеров использования функции filter:

<?php

use function Php\Pairs\Data\Lists\l;
use function Php\Pairs\Data\Lists\filter;
use function Php\Pairs\Data\Lists\toString;

$list = l('', 0, 10, 'go go', -5, 'string');
$list2 = filter($list, fn($element) => is_int($element));
print_r(toString($list2)); // => (0, 10, -5)

$list3 = filter($list, fn($element) => is_string($element));
print_r(toString($list3)); // => (, go go, string)

Как устроена фильтрация

<?php

function filter($list, callable $func)
{
    if (isEmpty($list)) {
        return l();
    }

    $current = head($list);
    $tailElements = tail($list);
    if ($func($current)) {
        return cons($current, filter($tailElements, $func));
    }
    return filter($tailElements, $func);
}

Посмотрим, как фильтрация устроена внутри. Это фактически тот же самый map. Мы получаем первый элемент с помощью функции head и после этого функцией func делаем проверку. В этом и заключается главное отличие. Если результат этой функции истина, то мы вызываем cons, т.е. добавляем текущий элемент в новый список. Если она возвращает false, то мы рекурсивно запускаем фильтр, пропуская этот элемент.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»
Изображение Тото

Задавайте вопросы, если хотите обсудить теорию или упражнения. Команда поддержки Хекслета и опытные участники сообщества помогут найти ответы и решить задачу