Во многих языках программирования есть очень полезная функция flatten()
, которая сильно упрощает жизнь и сокращает количество кода. Эта функция принимает на вход массив и выправляет его. Для примера представим, что мы работаем с массивом, в котором каждый элемент — это массив. В таком случае flatten()
раскроет каждый вложенный массив и сведет всё к одному массиву.
Так это работает на практике:
<?php
flatten([[3, 2], 5, 3, [3, [4, 2]], 10]);
// [3, 2, 5, 3, 3, 4, 2, 10]
Давайте напишем функцию flatten()
. В общем случае эта функция раскрывает массивы на всех уровнях вложенности. Чтобы было проще, сделаем вариант функции, в котором происходит раскрытие только до первого уровня. Другими словами, если элемент основного массива — это массив, то наша функция раскроет его без просмотра его внутренностей (несмотря на то, что там тоже могут быть массивы).
Логика работы нашей будущей функции выглядит так:
- Инициализируем массив-результат, в который запишутся все значения
- Проходим по основному массиву и проверяем текущий элемент
- Если текущий элемент — не массив, то добавляем его в массив-результат и идем дальше
- Если текущий элемент — массив, то начинаем вложенный цикл, внутри которого идем по массиву и добавляем каждый его элемент в массив-результат
- Возвращаем массив-результат
Перейдем к коду:
<?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);
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.