Как правильно рассчитать количество уровней в массиве? - PullRequest
2 голосов
/ 23 декабря 2009

У меня есть функция, которая должна принимать массив точек или массив точек (2 или 3-мерный массив). Я ищу надежный способ определить, имеет ли он 2 или 3 уровня. Дело в том, что я не могу рассчитывать на ключи массивов, чтобы выполнить проверку, так что это не работа:

$levels = isset($array[0][0]) && is_array($array[0][0]) ? 3 : 2;

.. поскольку первый ключ может не быть 0. Обычно это так, но я не хочу на это полагаться. И в любом случае, это дерьмовый и недалекий способ сделать это. Оптимально, я хотел бы проверить на любое количество уровней без необходимости проходить через весь массив.

Вот как могут выглядеть массивы:

array(5) {
    [2] => array(2) {
        [x] => 3
        [y] => 6
    }
    [3] => array(2) {
        [x] => 4
        [y] => 8
    }
    ...

И трехмерный массив будет содержать эти массивы.

Некоторые заметки:

  • Массивы большие, поэтому полный цикл по массивам не очень хороший вариант
  • Массивы индексируются численно и последовательно (за исключением последнего уровня, в котором есть x и y)
  • Ключи массива могут начинаться или не начинаться с 0

При написании этого я нашел решение, которое могло бы быть осуществимым; рекурсивная функция, которая проверяет первый элемент массива, если он есть, затем вызывает себя во вновь найденном массиве и т. д.

Есть ли лучшие, более чистые идеи? Бонусные баллы за поддержку массивов, которые могут иметь как скалярные значения, так и массивы (например, первый элемент массива может быть строкой, а следующий - массивом).

Ответы [ 3 ]

5 голосов
/ 23 декабря 2009

Если вы ожидаете полный массив или полный массив массивов, то вы можете попробовать: -

if (isset $points[0][0][0])

Если, однако, ваш массив разрежен, его сложнее. Основная проблема в том, что php "массив" на самом деле является одномерным хешем. Хитрость в том, что значение может быть другим «массивом». Поэтому вам необходимо получить доступ ко второму уровню, чтобы определить, является ли оно значением или массивом.

Опять же, если вы ожидаете, что данный массив будет содержать только значения точек или только другие массивы, вам нужно проверить только одну запись, так:

if ( is_array(current(current($points))) )

Должно дать вам то, что вы хотите: функция current () возвращает текущий указатель массива (по умолчанию первый - так что он всегда будет установлен на что-то), поэтому внутренний ток ($ points ) получит вам $ points [0] или первую запись с фактическим значением, аналогично внешнему току вы получите что-то вроде $ points [0] [0].

2 голосов
/ 23 декабря 2009

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

При этом, вы все равно можете использовать рекурсию, чтобы немного улучшить свой код:

/** 
 * Determine the maximum depth of an array.
 * @param $input The object to test. Might be an array, or might be an int (or
 *        any other object).
 * @param $startDepth The starting depth. Will be added as an offset to the
 *        result.
 * @return The depth of the array, plus any initial offset specified in
 *         $startDepth.
 */
function testDepth($input, $startDepth = 0) {
    if (is_array($input)) {
        $max = $startDepth;
        foreach ($input as $i) {
            // Check what the depth of the given element is
            $result = testDepth($i, $startDepth + 1);
            // We only care about the maximum value
            if ($result > $max) {
                $max = $result;
            }
        }
        return $max;
    } else {
        // This isn't an array, so it's assumed not to be a container.
        // This doesn't add any depth to the parent array, so just return $startDepth
        return $startDepth;
    }
}

testDepth($array);
1 голос
/ 23 декабря 2009

$ level = is_array (current (current ($ array)))? 3: 2;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...