Можно ли подсчитать количество измерений в массиве?
Я хочу иметь возможность знать уровень массива по мере его построения.
Код перебирает множество каталогов, чтобы создать массивный многомерный массив.
Поскольку массив создается, я хочу знать, насколько глубоко я нахожусь в массиве.
1 2 3 4
---------------------
Root
A
A2
A3
A4
A4a
B
B2
B3
C
D
E
E2
E2a
E3
В приведенном выше примере корневой каталог находится на уровне 1. Все одиночные прописные буквы находятся на уровне 2. Все заглавные буквы с цифрой находятся на уровне 3. Все прописные буквы с цифрой и строчными буквами буквы находятся на уровне 4.
Когда я строю массив, есть ли какой-нибудь способ узнать, на каком уровне я нахожусь? Массив создается с помощью рекурсивной функции.
Это вопрос PHP.
5 answers
Один быстрый и простой ответ - просто добавить параметр "глубина" в вашу функцию и увеличивать его, когда функция вызывает саму себя.
Это может касаться вашего вопроса о массиве, но вы можете убить двух зайцев одним выстрелом, используя рекурсивный итератор каталогов.
$path_to_root = __DIR__;
$directories = new ParentIterator(new RecursiveDirectoryIterator($path_to_root, RecursiveDirectoryIterator::CURRENT_AS_SELF));
$iterator = new RecursiveIteratorIterator($directories, RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $item)
{
printf("%d %s\n", $iterator->getDepth() + 1, $item->getSubPathname());
}
, который выводил бы что-то вроде:
1 Root
2 Root/A
3 Root/A/A2
3 Root/A/A3
3 Root/A/A4
4 Root/A/A4/A4a
2 Root/B
3 Root/B/B2
3 Root/B/B3
2 Root/C
2 Root/D
2 Root/E
3 Root/E/E2
4 Root/E/E2/E2a
3 Root/E/E3
Как вы можете видеть, RecursiveIteratorIterator::getDepth()
используется для получения текущей глубины рекурсивного итератора, что является причиной предложения этого подхода.
Альтернатива (если необходимо использовать массив)
Предполагая, что ваша структура массива выглядит как-то например:
$dirs = array(
'Root' => array(
'A' => array(
'A2' => array(),
'A3' => array(),
'A4' => array(
'A4a' => array(),
),
),
'B' => array(
'B2' => array(),
'B3' => array(),
),
'C' => array(),
'D' => array(),
'E' => array(
'E2' => array(
'E2a' => array(),
),
'E3' => array(),
),
),
);
Затем можно использовать очень похожий подход к получению значений из рекурсивного итератора каталогов (но на этот раз с рекурсивным итератором массива). Быстрый цикл по "родительским" массивам может дать нам "путь" от текущего элемента обратно к корню.
$recursive = new ParentIterator(new RecursiveArrayiterator($dirs));
$iterator = new RecursiveIteratorIterator($recursive, RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $item)
{
// Build path from "parent" array keys
for ($path = "", $i = 0; $i <= $iterator->getDepth(); $i++) {
$path .= "/" . $iterator->getSubIterator($i)->key();
}
// Output depth and "path"
printf("%d %s\n", $iterator->getDepth() + 1, ltrim($path, "/"));
}
Вывод будет таким же, как и предыдущий для итератора каталогов.
TL;DR Мы можем использовать рекурсивные итераторы из итераторов SPL, чтобы работать с рекурсивные/глубокие структуры намного проще.
TL;DR;TL;DR SPL, черт возьми, да!
Это должно сделать:
function array_depth($array) {
$max_depth = 1;
foreach ($array as $value) {
if (is_array($value)) {
$depth = array_depth($value) + 1;
if ($depth > $max_depth) {
$max_depth = $depth;
}
}
}
return $max_depth;
}
function calc_dimensions(array $array) {
$dimensions = 1;
$max = 0;
foreach ($array as $value) {
if (is_array($value)) {
$subDimensions = calc_dimensions($value);
if ($subDimensions > $max) {
$max = $subDimensions;
}
}
}
return $dimensions+$max;
}
$array = array(
array(
array(
4 => 5,
array(
6 => 6
)
)
),
1 => 5
);
echo calc_dimensions($array)."\n";
Возможно, вы задаете неправильный вопрос. Какова конечная цель? Например, в SPL есть класс RecursiveDirectoryIterator, может быть, это подойдет для вас? Создание большого многомерного массива потребует много памяти, так что, может быть, достаточно просто рекурсивно перебирать все эти файлы?