PHP如何确定在foreach循环的第一个和最后一个迭代?

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

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

在这个循环中,当我们在第一次或最后一次迭代时,我希望做出不同的反应。

如何做到这一点?

718961 次浏览

你可以用一个计数器:

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

您可以从数组中删除第一个和最后一个元素,并分别处理它们。

是这样的:

<?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) {
//retrieve 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
}
?>

1:为什么不使用简单的for语句?假设您正在使用一个真实的数组,而不是Iterator,您可以很容易地检查counter变量是0还是比元素的总数少1。在我看来,这是最干净、最容易理解的解决方案……

$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:你应该考虑使用嵌套组来存储你的树结构。此外,您可以通过使用递归函数来改进整个过程。

上面的一个更简化的版本,并假设您不使用自定义索引……

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

版本2 -因为我已经讨厌使用else除非必要。

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


if ($index == $len - 1) {
// last
// do something
continue;
}
}

对于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: 100000次模型morg

时间:1869.3430423737毫秒

Test2:模型运行100000次

时间:3235.6359958649毫秒

因此,很明显,支票的成本很高,当然,你添加的变量越多,情况就越糟糕;)

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

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 7.2及以上版本:

PHP 7.2已经是EOL(生命终结),所以这里只是作为历史参考。避免使用。

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


end($array);
if ($key === key($array)) {
echo 'LAST ELEMENT!';
}
}

试试这个:

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);

最佳答案:

$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";


}

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

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

要找到第一个,可以这样做:

$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
}
}

对于键和值,这也是有效的:

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

不确定是否还有必要。但是下面的解决方案应该使用迭代器,并且不需要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;
}
}
}

使用布尔变量仍然是最可靠的,即使你想检查$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++;
}

这很简单!

// Set the array pointer to the last key
end($array);
// Store the last key
$lastkey = key($array);
foreach($array as $key => $element) {
....do array stuff
if ($lastkey === key($array))
echo 'THE LAST ELEMENT! '.$array[$lastkey];
}

感谢@billynoah解决了结束问题。

@morg中的有效的答案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++;

我还没有对此进行基准测试,但没有向循环添加逻辑,这是对性能影响最大的地方,因此我怀疑提供有效答案的基准测试非常接近。

如果你想要使职能化这种事情,我已经采取了这样的这里的iterateList函数。不过,如果您非常关心效率,您可能需要对主旨代码进行基准测试。我不确定所有函数调用引入了多少开销。

当我遇到同样的问题时,我遇到了这条线索。我只需要得到第一个元素,然后我重新分析我的代码,直到这出现在我的脑海中。

$firstElement = true;


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

上面的代码是伟大的和完整的,但如果你只需要第一个元素,那么你可以试试这段代码。

你也可以使用匿名函数:

$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旁边,如果需要也可以引用。

可以使用计数器和数组长度。

$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++;
}
foreach ($arquivos as $key => $item) {
reset($arquivos);
// FIRST AHEAD
if ($key === key($arquivos) || $key !== end(array_keys($arquivos)))
$pdf->cat(null, null, $key);


// LAST
if ($key === end(array_keys($arquivos))) {
$pdf->cat(null, null, $key)
->execute();
}
}

使用重置(数组)结束(数组)

<?php


$arrays = [1,2,3,4,5];


$first  = reset($arrays);
$last   = end($arrays);


foreach( $arrays as $array )
{


if ( $first == $array )
{
echo "<li>{$array} first</li>";
}
else if ( $last == $array )
{
echo "<li>{$array} last</li>";
}
else
{
echo "<li>{$array}</li>";
}


}

< a href = " https://repl。it/@antelove19/phparrayresetloop" rel="nofollow noreferrer">Demo repit .it

最简单的方法是

$array = [9,5,6,4,7,8];


$current_iteration = 0;


foreach($array as $item){
if( 0 === $current_iteration ){
echo 'this is the first item: ' . $item;
}


if( (count($array) - 1) === $current_iteration){
echo 'this is the last item: ' . $item;
}


$current_iteration++;
}