Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Вложенные циклы PHP: Массивы

Во многих языках программирования есть очень полезная функция flatten(), которая сильно упрощает жизнь и сокращает количество кода. Эта функция принимает на вход массив и выправляет его. Для примера представим, что мы работаем с массивом, в котором каждый элемент — это массив. В таком случае flatten() раскроет каждый вложенный массив и сведет всё к одному массиву.

Так это работает на практике:

<?php

flatten([[3, 2], 5, 3, [3, [4, 2]], 10]);
// [3, 2, 5, 3, 3, 4, 2, 10]

Давайте напишем функцию flatten(). В общем случае эта функция раскрывает массивы на всех уровнях вложенности. Чтобы было проще, сделаем вариант функции, в котором происходит раскрытие только до первого уровня. Другими словами, если элемент основного массива — это массив, то наша функция раскроет его без просмотра его внутренностей (несмотря на то, что там тоже могут быть массивы).

Логика работы нашей будущей функции выглядит так:

  1. Инициализируем массив-результат, в который запишутся все значения
  2. Проходим по основному массиву и проверяем текущий элемент
    • Если текущий элемент — не массив, то добавляем его в массив-результат и идем дальше
    • Если текущий элемент — массив, то начинаем вложенный цикл, внутри которого идем по массиву и добавляем каждый его элемент в массив-результат
  3. Возвращаем массив-результат

Перейдем к коду:

<?php

function flatten($coll)
{
    $result = [];
    foreach ($coll as $item) {
        // Ниже будет функция is_array — это предикат стандартной библиотеки
        // Она проверяет, является ли значение массивом
        if (is_array($item)) {
            // Если значение — это массив, проходим по всем его элементам
            // Здесь появился вложенный цикл
            foreach ($item as $subitem) {
                // Добавляем элементы в результирующий массив
                $result[] = $subitem;
            }
        } else {
            // Если значение — это не массив, сразу добавляем его в результирующий массив
            $result[] = $item;
        }
    }

    return $result;
}

print_r(flatten([3, 2, [], [3, 4, 2], 3, [123, 3]]));
// => Array
// => (
// =>     [0] => 3
// =>     [1] => 2
// =>     [2] => 3
// =>     [3] => 4
// =>     [4] => 2
// =>     [5] => 3
// =>     [6] => 123
// =>     [7] => 3
// => )

https://repl.it/@hexlet/php-arrays-nested-loops-flatten

В коде выше видно, что вложенный цикл запускается только в том случае, если текущий элемент — массив.

Чисто технически во вложенных циклах нет ничего особенного. Их можно вкладывать внутрь любого блока и друг в друга сколько угодно раз. При этом нет прямой связи между внешним и вложенным циклом. Внутренний цикл может использовать результаты внешнего, а может и не использовать. Тогда он будет работать независимо по своей логике.

Но не стоит забывать, что вложенные циклы коварны. Они могут создать много постоянно меняющихся переменных. Код станет намного сложнее для восприятия, будет сложно уследить за происходящими внутри процессами. Кроме того, вложенные циклы могут намекать, что мы используем неэффективный алгоритм решения задачи. Это не всегда так, но такая вероятность есть.

Как избавиться от вложенных циклов? Есть два варианта:

  • Переписать алгоритм и убрать вложенный цикл везде, даже в вызываемых функциях
  • Вынести вложенный цикл в функцию или заменить его на встроенную функцию

Первый вариант не всегда возможен, поэтому важно научиться применять второй вариант.

Чтобы избавиться от вложенных циклов, применим функцию array_search. По сути, это обход массива в цикле:

<?php

// Эта функция заменяет цикл
// Не забывайте, что внутри функции все равно происходит полный обход массива
array_search(10, [1, 10, 3]); // 1

Рассмотрим пример выноса в отдельную функцию кода с функцией flatten():

<?php

function concat($result, $items)
{
    foreach ($items as $item) {
        $result[] = $item;
    }
    return $result;
}

function flatten($coll)
{
    $result = [];
    foreach ($coll as $item) {
        if (is_array($item)) {
            $result = concat($result, $item);
        } else {
            $result[] = $item;
        }
    }

    return $result;
}

print_r(flatten([3, 2, [], [3, 4, 2], 3, [123, 3]]));

Этот код можно сделать еще проще, если использовать встроенную функцию array_merge(). Тогда код слияния массивов будет выглядеть так:

<?php

$result = array_merge($result, $item);

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

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

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

Об обучении на Хекслете

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

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

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

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

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

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

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

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Разработка веб-приложений на Laravel
10 месяцев
с нуля
Старт 25 апреля

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

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

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

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