How to determine the first and last iteration in a foreach loop?
问题很简单。我的代码中有一个
1 2 3 | foreach($array as $element) { //code } |
在这个循环中,我希望在第一次或最后一次迭代中有不同的反应。
如何做到这一点?
如果您喜欢不需要在循环外初始化计数器的解决方案,我建议将当前迭代键与告诉您数组的最后/第一个键的函数进行比较。
在即将到来的PHP7.3中,这变得更加高效(和更可读)。
PHP 7.3及以上版本的解决方案:1 2 3 4 5 6 7 | foreach($array as $key => $element) { if ($key === array_key_first($array)) echo 'FIRST ELEMENT!'; if ($key === array_key_last($array)) echo 'LAST ELEMENT!'; } |
所有PHP版本的解决方案:
1 2 3 4 5 6 7 8 9 |
您可以使用计数器:
1 2 3 4 5 6 7 8 9 10 11 | $i = 0; $len = count($array); foreach ($array as $item) { if ($i == 0) { // first } else if ($i == $len - 1) { // last } // … $i++; } |
为了找到最后一项,我发现这段代码每次都有效:
1 2 3 4 5 |
更简单的版本,假设您没有使用自定义索引…
1 2 3 4 5 6 7 8 | $len = count($array); foreach ($array as $index => $item) { if ($index == 0) { // first } else if ($index == $len - 1) { // last } } |
第二版-因为我不喜欢在必要的时候使用其他版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $len = count($array); foreach ($array as $index => $item) { if ($index == 0) { // first // do something continue; } if ($index == $len - 1) { // last // do something continue; } } |
您可以从数组中删除第一个和最后一个元素,然后分别处理它们。这样地:
1 2 3 4 5 6 7 8 9 10 11 | <?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逻辑混合在一起。通过将以下内容分开,可以使您的页面更易于阅读和维护:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <?php function create_menu($params) { //retirive menu items //get collection $collection = get('xxcollection') ; foreach($collection as $c) show_collection($c); } function show_subcat($val) { ?> <img src="../images/dtree/join.gif" align="absmiddle" style="padding-left:2px;" /> <?php echo $val['xsubcatname']; ?> <?php } function show_cat($item) { ?> <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); ?> <?php } function show_collection($c) { ?> <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); ?> <?php } ?> |
试图找到第一个的方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $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 } } |
这很简单!
1 2 3 4 5 6 7 8 9 |
感谢@billynoah为您解决最终问题。
1:为什么不使用一个简单的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
2:应该考虑使用嵌套集来存储树结构。此外,还可以使用递归函数来改进整个过程。
最佳答案:
1 2 3 4 5 6 7 8 9 10 11 12 |
@morg提供的最有效的答案与
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | $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++; |
我还没有在这方面做基准测试,但是循环中没有添加任何逻辑,这是性能发生的最大冲击,所以我怀疑提供有效答案的基准非常接近。
如果你想实现这类功能,我在这里讨论了一个迭代列表函数。尽管如此,如果您非常关心效率,那么您可能需要对gist代码进行基准测试。我不确定所有函数调用都会带来多少开销。
对于生成脚本的SQL查询,或者对第一个或最后一个元素执行不同操作的任何操作,避免使用不必要的变量检查的速度要快得多(几乎快两倍)。
当前接受的解决方案使用循环和循环内的检查,每次迭代都要进行检查,正确(快速)的方法如下:
1 2 3 4 5 6 7 8 9 10 | $numItems = count($arr); $i=0; $firstitem=$arr[0]; $i++; while($i<$numItems-1){ $some_item=$arr[$i]; $i++; } $last_item=$arr[$i]; $i++; |
一个自制的小基准显示了以下内容:
试验1:100000次模型试验
时间:1869.3430423737毫秒
测试2:100000次模型运行(如果最后一次)
时间:3235.6359958649毫秒
因此很明显,支票的成本很高,当然,您添加的可变支票越多,情况就越糟糕;)
对于键和值,这也适用:
1 2 3 4 5 |
使用布尔变量仍然是最可靠的,即使您想检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | $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'; } } |
那么,如果没有
如果我要使用一个计数器,我更喜欢使用
1 2 3 4 5 6 7 8 9 10 11 | $len = count( $array ); for ( $i = 0; $i < $len; $i++ ) { $value = $array[$i]; if ($i === 0) { // first } elseif ( $i === $len - 1 ) { // last } // … $i++; } |
当我遇到同样的问题时,我遇到了这个问题。我只需要得到第一个元素,然后重新分析我的代码,直到我想到这一点。
1 2 3 4 5 6 7 | $firstElement = true; foreach ($reportData->result() as $row) { if($firstElement) { echo"first element"; $firstElement=false; } // Other lines of codes here } |
上面的代码很好而且很完整,但是如果您只需要第一个元素,那么您可以尝试使用这个代码。
不确定是否还有必要。但是下面的解决方案应该与迭代器一起工作,不需要
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?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; } } } |
您可以使用计数器和数组长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
您也可以使用匿名函数:
1 2 3 4 5 6 7 8 9 10 | $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 旁边列出,如果需要,也可以通过引用列出。
试试这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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) . '">' . $child['name'] . ' </li> '; $class = array(); $list .= children($parents, $child['id'], $selected); } $list .= ' </ul> '; return $list; } } $output .= children( $parents, 0, $p_industry_id); |