首页 文章

如何确定foreach循环中的第一次和最后一次迭代?

提问于
浏览
420

问题很简单 . 我的代码中有一个 foreach 循环:

foreach($array as $element) {
    //code
}

在这个循环中,我想在第一次或最后一次迭代时做出不同的反应 .

这该怎么做?

19 回答

  • 6

    你可以用一个柜台:

    $i = 0;
    $len = count($array);
    foreach ($array as $item) {
        if ($i == 0) {
            // first
        } else if ($i == $len - 1) {
            // last
        }
        // …
        $i++;
    }
    
  • 32

    如果您更喜欢不需要在循环外部初始化计数器的解决方案,我建议将当前迭代键与告诉您数组的最后/第一个键的函数进行比较 .

    即将推出的PHP 7.3,这会变得更有效(并且更具可读性) .

    PHP 7.3及更高版本的解决方案:

    foreach($array as $key => $element) {
        if ($key === array_key_first($array))
            echo 'FIRST ELEMENT!';
    
        if ($key === array_key_last($array))
            echo 'LAST ELEMENT!';
    }
    

    所有PHP版本的解决方案:

    foreach($array as $key => $element) {
        reset($array);
        if ($key === key($array))
            echo 'FIRST ELEMENT!';
    
        end($array);
        if ($key === key($array))
            echo 'LAST ELEMENT!';
    }
    
  • 1

    为了找到最后一项,我发现这段代码每次都有效:

    foreach( $items as $item ) {
        if( !next( $items ) ) {
            echo 'Last Item';
        }
    }
    
  • 361

    上面的更简化版本并假设您没有使用自定义索引...

    $len = count($array);
    foreach ($array as $index => $item) {
        if ($index == 0) {
            // first
        } else if ($index == $len - 1) {
            // last
        }
    }
    

    版本2 - 因为除非必要,否则我会厌恶使用其他 .

    $len = count($array);
    foreach ($array as $index => $item) {
        if ($index == 0) {
            // first
            // do something
            continue;
        }
    
        if ($index == $len - 1) {
            // last
            // do something
            continue;
        }
    }
    
  • 4

    您可以从阵列中删除第一个和最后一个元素并单独处理它们 .
    像这样:

    <?php
    $array = something();
    $first = array_shift($array);
    $last = array_pop($array);
    
    // do something with $first
    foreach ($array as $item) {
     // do something with $item
    }
    // do something with $last
    ?>
    

    删除所有格式设置为CSS而不是内联标记将改善您的代码并加快加载时间 .

    您也可以尽可能避免将HTML与PHP逻辑混合使用 .
    通过分离这样的内容,可以使您的页面更具可读性和可维护性:

    <?php
    function create_menu($params) {
      //retirive menu items 
      //get collection 
      $collection = get('xxcollection') ;
      foreach($collection as $c) show_collection($c);
    }
    
    function show_subcat($val) {
      ?>
        <div class="sub_node" style="display:none">
          <img src="../images/dtree/join.gif" align="absmiddle" style="padding-left:2px;" />
          <a id="'.$val['xsubcatid'].'" href="javascript:void(0)" onclick="getProduct(this , event)" class="sub_node_links"  >
            <?php echo $val['xsubcatname']; ?>
          </a>
        </div>
      <?php
    }
    
    function show_cat($item) {
      ?>
        <div class="node" >
          <img src="../images/dtree/plus.gif" align="absmiddle" class="node_item" id="plus" />
          <img src="../images/dtree/folder.gif" align="absmiddle" id="folder">
          <?php echo $item['xcatname']; ?>
          <?php 
            $subcat = get_where('xxsubcategory' , array('xcatid'=>$item['xcatid'])) ;
            foreach($subcat as $val) show_subcat($val);
          ?>
        </div>
      <?php
    }
    
    function show_collection($c) {
      ?>
        <div class="parent" style="direction:rtl">
          <img src="../images/dtree/minus.gif" align="absmiddle" class="parent_item" id="minus" />
          <img src="../images/dtree/base.gif" align="absmiddle" id="base">
          <?php echo $c['xcollectionname']; ?>
          <?php
            //get categories 
            $cat = get_where('xxcategory' , array('xcollectionid'=>$c['xcollectionid']));
            foreach($cat as $item) show_cat($item);
          ?>
        </div>
      <?php
    }
    ?>
    
  • 14

    尝试找到第一个将是:

    $first = true; 
    foreach ( $obj as $value )
    {
      if ( $first )
      {
        // do something
        $first = false; //in order not to get into the if statement for the next loops
      }
      else
      {
        // do something else for all loops except the first
      }
    }
    
  • 3

    这很有效!

    //Store the last key
    $lastkey = key(end($array)); 
    foreach($array as $key => $element) {
        ....do array stuff
        if ($lastkey === key($array))
            echo 'LAST ELEMENT!';
    }
    
  • 86

    1:为什么不使用简单的 for 语句?假设您使用的是真实数组而不是 Iterator ,您可以轻松检查计数器变量是0还是小于整数个元素 . 在我看来,这是最干净,最容易理解的解决方案......

    $array = array( ... );
    
    $count = count( $array );
    
    for ( $i = 0; $i < $count; $i++ )
    {
    
        $current = $array[ $i ];
    
        if ( $i == 0 )
        {
    
            // process first element
    
        }
    
        if ( $i == $count - 1 )
        {
    
            // process last element
    
        }
    
    }
    

    2:您应该考虑使用Nested Sets来存储您的树结构 . 此外,您可以使用递归函数来改进整个过程 .

  • 0

    最佳答案:

    $arr = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    
    foreach ($arr as $a) {
    
    // This is the line that does the checking
    if (!each($arr)) echo "End!\n";
    
    echo $a."\n";
    
    }
    
  • 0

    来自@morg的最多efficient answer,与 foreach 不同,仅适用于正确的数组,而不适用于哈希映射对象 . 这个答案避免了循环的每次迭代的条件语句的开销,就像在大多数这些答案(包括接受的答案)中一样,通过专门处理第一个和最后一个元素,并循环中间元素 .

    array_keys函数可用于使高效答案像 foreach 一样工作:

    $keys = array_keys($arr);
    $numItems = count($keys);
    $i=0;
    
    $firstItem=$arr[$keys[0]];
    
    # Special handling of the first item goes here
    
    $i++;
    while($i<$numItems-1){
        $item=$arr[$keys[$i]];
        # Handling of regular items
        $i++;
    }
    
    $lastItem=$arr[$keys[$i]];
    
    # Special handling of the last item goes here
    
    $i++;
    

    我没有对此进行基准测试,但是没有逻辑添加到循环中,这是性能发生的最大打击,所以我怀疑提供高效答案的基准非常接近 .

    如果你想 functionalize 这种事情,我已经开始了这样的事情 . 虽然,如果您不确定所有函数调用引入了多少开销,您可能希望对gist代码进行基准测试 .

  • 72

    对于SQL查询生成脚本,或对第一个或最后一个元素执行不同操作的任何内容,它要快得多(几乎快两倍)以避免使用不必要的变量检查 .

    当前接受的解决方案在循环内使用循环和检查every_single_iteration,正确(快速)方式执行此操作如下:

    $numItems = count($arr);
    $i=0;
    $firstitem=$arr[0];
    $i++;
    while($i<$numItems-1){
        $some_item=$arr[$i];
        $i++;
    }
    $last_item=$arr[$i];
    $i++;
    

    一个小的自制基准显示如下:

    test1:模型morg的100000次运行

    时间:1869.3430423737毫秒

    test2:如果最后一次运行100000次模型

    时间:3235.6359958649毫秒

    因此很明显,检查费用很高,当然,你添加的变量检查越多,情况就越糟糕;)

  • 3

    使用布尔变量仍然是最可靠的,即使你想检查 $value 的第一次出现(我发现它在我的情况和许多情况下更有用),如下所示:

    $is_first = true;
    
    foreach( $array as $value ) {
        switch ( $value ) {
            case 'match':
                echo 'appeared';
    
                if ( $is_first ) {
                    echo 'first appearance';
                    $is_first = false;
                }
    
                break;
            }
        }
    
        if( !next( $array ) ) {
            echo 'last value';
        }
    }
    

    那么 !next( $array ) 怎么样找到最后的 $value ,如果没有 next() 值要迭代,它将返回 true .

    如果我打算使用计数器,我更喜欢使用 for 循环而不是 foreach ,如下所示:

    $len = count( $array );
    for ( $i = 0; $i < $len; $i++ ) {
        $value = $array[$i];
        if ($i === 0) {
            // first
        } elseif ( $i === $len - 1 ) {
            // last
        }
        // …
        $i++;
    }
    
  • 10

    使用Keys和Values也可以:

    foreach ($array as $key => $value) {
        if ($value === end($array)) {
            echo "LAST ELEMENT!";
        }
    }
    
  • 8

    当我遇到同样的问题时,我遇到了这个帖子 . 我只需要获得第一个元素然后重新分析我的代码,直到我想到这一点 .

    $firstElement = true;
    
    foreach ($reportData->result() as $row) 
    {
           if($firstElement) { echo "first element"; $firstElement=false; }
           // Other lines of codes here
    }
    

    上面的代码非常完整,但如果您只需要第一个元素,那么您可以尝试使用此代码 .

  • -1

    不确定是否还有必要 . 但是以下解决方案应该与迭代器一起使用,并且不需要 count .

    <?php
    
    foreach_first_last(array(), function ($key, $value, $step, $first, $last) {
        echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
    });
    
    foreach_first_last(array('aa'), function ($key, $value, $step, $first, $last) {
        echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
    });
    echo PHP_EOL;
    
    foreach_first_last(array('aa', 'bb', 'cc'), function ($key, $value, $step, $first, $last) {
        echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
    });
    echo PHP_EOL;
    
    function foreach_first_last($array, $cb)
    {
        $next = false;
        $current = false;
        reset($array);
        for ($step = 0; true; ++$step) {
            $current = $next;
            $next = each($array);
            $last = ($next === false || $next === null);
            if ($step > 0) {
                $first = $step == 1;
                list ($key, $value) = $current;
                if (call_user_func($cb, $key, $value, $step, $first, $last) === false) {
                    break;
                }
            }
            if ($last) {
                break;
            }
        }
    }
    
  • 0

    您也可以使用匿名函数:

    $indexOfLastElement = count($array) - 1;
    array_walk($array, function($element, $index) use ($indexOfLastElement) {
        // do something
        if (0 === $index) {
            // first element‘s treatment
        }
        if ($indexOfLastElement === $index) {
            // last not least
        }
    });
    

    还应该提到三件事:

    • 如果您的数组没有严格(数字)索引,则必须先将数组通过 array_values .

    • 如果您需要修改 $element ,您必须通过引用传递它( &$element ) .

    • 你需要在匿名函数之外的任何变量,你必须在 use 构造内的 $indexOfLastElement 旁边列出它们,再次通过引用列出需要 .

  • 14

    您可以使用计数器和数组长度 .

    $array = array(1,2,3,4);
    
        $i = 0;
        $len = count($array);
        foreach ($array as $item) {
            if ($i === 0) {
                // first
            } else if ($i === $len - 1) {
                // last
            }
            // …
            $i++;
        }
    
  • 5

    最简单的方法:

    foreach($array as $value) {
    
        if ($value === reset($array)) {
            echo 'FIRST ELEMENT!';
        }
    
        if ($value === end($array)) {
            echo 'LAST ITEM!';
        }
    
    }
    
  • 868

    试试这个:

    function children( &$parents, $parent, $selected ){
      if ($parents[$parent]){
        $list = '<ul>';
        $counter = count($parents[$parent]);
        $class = array('first');
        foreach ($parents[$parent] as $child){
          if ($child['id'] == $selected)  $class[] = 'active';
          if (!--$counter) $class[] = 'last';
          $list .= '<li class="' . implode(' ', $class) . '"><div><a href="]?id=' . $child['id'] . '" alt="' . $child['name'] . '">' . $child['name'] . '</a></div></li>';
          $class = array();
          $list .= children($parents, $child['id'], $selected);
        }
        $list .= '</ul>';
        return $list;
      }
    }
    $output .= children( $parents, 0, $p_industry_id);
    

相关问题