Обнаружение «фактического» конца массива в PHP - PullRequest
3 голосов
/ 04 августа 2011

Учитывая, что у меня есть массив следующим образом:

$array = array('a', 'b', 0, 'c', null, 'd');

Теперь я могу легко выполнить итерацию с помощью foreach, конечно:

foreach($array as $value){
    var_dump($value);
}

И все хорошо и хорошо. Однако, если я хочу выполнить « peek », чтобы проверить, нахожусь ли я на последнем элементе, следующее не сработает:

reset($array);
while($value = current($array)){
    var_dump($value);
    if(next($array)){
        // this won't be accurate because of the 0 element
    }
}

Хорошо, я провожу более строгий тест:

if(null !== next($array)){
    // this STILL won't be accurate because of the null element
}

Является ли единственным решением использовать индексированный цикл for с арифметическим подсмотром? Я не считаю это жизнеспособным для поддержания целостности ассоциативного ключа без большого количества безделья. ( Я знаю, что мой пример не является примером этого предостережения, но я бы поменял current() на each() и next() на current())

Нет ли надежного способа точно определить, переместился ли указатель массива за конец массива, независимо от значений элемента массива (null, 0 и т. Д. )

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


Ну, это ни в коем случае не идеальное решение, , поскольку array_keys() создает новый массив Примечание , но здесь идет речь:

$array = array('alpha', 'b' => 'beta', null, 'g' => 'gamma', false, 0, 'delta', null);
list($end) = array_keys(array_slice($array, -1, 1, true));
foreach($array as $key => &$value){
    // do important stuff on each element
    if($key !== $end){
        // do important stuff on all but last element
    }
}

Примечание Я поменял местами array_slice() и array_keys(), поэтому полная копия ключа не создана. Первоначально это было: array_slice(array_keys($array), -1);, похоже, ревизия будет лучше по памяти.


Еще одно редактирование для тех, кто спотыкается здесь; они могут быть полезны в подобных ситуациях:

// each returns the current element, but assigns to the referenced arguments
// the "peeked" values. they're missing checks, but it's a start.

function peek(Array &$array, &$value){
    $value = next($array);
    return prev($array);
}

function peek_key(Array &$array, &$key){
    next($array);
    $key = key($array);
    return prev($array);
}

function peek_each(Array &$array, &$key, &$value){
    next($array);
    list($key, $value) = array(key($array), current($array));
    return prev($array);
}

Ответы [ 4 ]

5 голосов
/ 04 августа 2011

http://www.php.net/next
Примечание. Вы не сможете отличить конец массива от логического элемента FALSE.Чтобы правильно пройти массив, который может содержать FALSE элементов, см. Функцию each().

while (list($key, $val) = each($fruit)) {
    echo "$key => $val\n";
}

each возвращает массив или false.Это очень однозначно различимо.

4 голосов
/ 04 августа 2011

Что плохого в подсчете количества элементов? И используя это, чтобы определить, нахожусь ли я на последнем элементе? http://codepad.org/zTRRjLdl

$myArr = $array = array('a', 'b', 0, 'c', null, 'd');
$count = count($myArr);
$index = 0;

foreach($myArr as $value)
{

   var_dump($value);
   $index++;
   if($index == $count)   
      echo "Its the last one here :)";
}
0 голосов
/ 15 августа 2013

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

$arr = array('alpha', 'b' => 'beta', null, 'g' => 'gamma', false, 0, 'delta', null);

if (!empty($arr)) {
   while (TRUE) {
       // advance and rewind the internal array pointer to do useful things
       // (note that this example doesn't cover rewinding the internal array
       // pointer too far)
       if (array_end($arr)) {
           break;
       }
   }
}

/**
 * Detect the end of an array
 * @return boolean TRUE if we've reached the end of the array or exceeded its bounds
 */
function array_end(array $arr) {
    $currentKey = key($arr);
    if (NULL === $currentKey) {
        // we've moved beyond the bounds of the array
        return TRUE;
    }
    $lastKey = key(array_slice($arr, -1, 1, TRUE));
    return ($currentKey === $lastKey);
}
0 голосов
/ 09 августа 2011

Ну, вот что я закончил:

$array = array('alpha', 'b' => 'beta', null, 'g' => 'gamma', false, 0, 'delta', null);

if(!empty($array)){
    list($end) = array_keys(array_slice($array, -1, 1, true));
    foreach($array as $key => &$value){
        // do important stuff on each element
        if($key !== $end){
            // do important stuff on all but last element
        }
    }
}

В любом случае, не стесняйтесь отвечать, если у вас есть лучшее решение.Это работает, но я с радостью приму что-нибудь получше.

...