在使用PHP的foreach循环时查找数组的最后一个元素

255

我正在编写一个使用一些参数的 SQL 查询生成器。在 Java 中,通过检查当前数组位置与数组长度,很容易从 for 循环内部检测到数组的最后一个元素。

for(int i=0; i< arr.length;i++){
     boolean isLastElem = i== (arr.length -1) ? true : false;        
}
在PHP中,它们有非整数索引来访问数组。因此,您必须使用foreach循环迭代数组。当您需要做出一些决定时(在我的情况下是在构建查询时附加和/或参数),这变得很棘手。
我相信一定有某种标准的解决方法。
您如何在PHP中解决这个问题?

2
你是否在尝试确定在 where 子句的部分之间应该连接 "AND" 还是 "OR"? - Darryl Hein
1
只是指出,你应该将总数存储在一个变量中,而不是在每次迭代时调用一个方法。 for(int i=0, int t = arr.length; i<t;i++)。 - OIS
https://dev59.com/AHVC5IYBdhLWcg3w4VVz - xtofl
看一下这个解决方案:https://dev59.com/-XNA5IYBdhLWcg3wKaYx#29474468 - vbarbarosh
使用 end(array)。参考类似答案 - Visakh B Sujathan
你想用它做什么?你已经打算遍历它了吗?有一个end()函数可以将数组指针移动到数组的末尾,或者你也可以使用array_pop()函数来遍历它。 - Hayden
35个回答

362

你好像想要这样的东西:

$numItems = count($arr);
$i = 0;
foreach($arr as $key=>$value) {
  if(++$i === $numItems) {
    echo "last index!";
  }
}    

话虽如此,在PHP中您并不一定需要使用foreach来迭代一个“数组”。


24
在PHP中不需要使用$numItems = count($arr)技巧,这会降低代码可读性。因为在PHP中,每次访问count($arr)并不会影响性能,原因是数组头部内部保存了项目数量作为特殊字段,而不是动态计算。这个技巧来自其他语言(如C、Java等)。 - johndodo
7
很有趣,@johndodo,每次访问count($arr)都没有性能惩罚。你有任何链接或来源可以说明这个特定的优化吗?谢谢! - zuallauz
2
在 PHP 中,解决这个问题最正确的方法看起来相当不优雅 :( - kizzx2
1
@tomsihap 在循环内部需要增加 $i,与数组迭代同步。$i 需要表示数组中项目的编号,以便确定何时到达最后一个项目。如果没有 ++,循环将仅比较“0”和项目总数。 - Bobby Jack
1
自 PHP 7.3 至今,您可以使用 array_key_last($array) 获取数组的最后一个键的值。 - TechDogLover OR kiaNasirzadeh
显示剩余5条评论

229
您可以使用 end(array_keys($array)) 获取数组的最后一个键的值,并将其与当前键进行比较:
$last_key = end(array_keys($array));
foreach ($array as $key => $value) {
    if ($key == $last_key) {
        // last element
    } else {
        // not last element
    }
}

21
我自辩,我的回答并不依赖于数组有数值键 :) - Richard Levasseur
2
字符串比较比整数慢,并且当将字符串与整数进行比较时,不总是准确的(你至少应该使用 ===)。我会投反对票。 - OIS
4
它很优雅,但会引起“严格注意”,因为“end”需要一个引用值 :( - Wiliam
13
解决 STRICT NOTICE 报错:$lastKey = array_search(end($array), $array); - Ajax
2
这应该是获取数组最后一个键而不触发错误消息的最快方法:end($array); $last_key = key($array); - OIS
显示剩余3条评论

56

注意:这样不起作用,因为调用next()会推进数组指针,所以在循环中你会跳过每个其他元素。


为什么这么复杂?

foreach($input as $key => $value) {
    $ret .= "$value";
    if (next($input)==true) $ret .= ",";
}

这将在除了最后一个值之外的每个值后面添加一个逗号!


3
不要使用next()方法,因为它不能区分下一个$input是否包含布尔值false,这是一个严重的问题。 - soulseekah
39
如果我没有理解错的话,这个方法不起作用是因为调用 next() 会推进数组指针,所以在循环中你会跳过每隔一个元素。 - Jordan Lev
2
对我来说好像不起作用。倒数第二个元素没有逗号,但应该有。 - zuallauz
1
如果值等于布尔假,它就不起作用。同时也不会在倒数第二个和最后一个值之间打印最后一个逗号。 - OIS
2
想在PHP7中使用此代码的人需要注意 - 在foreach循环中,数组指针不会移动,因此这段代码将无法正常工作。 - Scott Flack
显示剩余2条评论

28

当toEnd达到0时,这意味着它在循环的最后一次迭代。

$toEnd = count($arr);
foreach($arr as $key=>$value) {
  if (0 === --$toEnd) {
    echo "last index! $value";
  }
}

循环结束后仍然可以使用最后一个值,所以如果你想在循环之后使用它进行更多的操作,那么这种方式更好:

foreach($arr as $key=>$value) {
  //something
}
echo "last index! $key => $value";

如果你不想在循环内把最后一个值视作特殊情况,这种方式在处理大型数组时会更快。 (如果你在同一作用域下的循环后要重复使用该数组,则需要先“复制”该数组)。

//If you use this in a large global code without namespaces or functions then you can copy the array like this:
//$array = $originalArrayName; //uncomment to copy an array you may use after this loop

//end($array); $lastKey = key($array); //uncomment if you use the keys
$lastValue = array_pop($array);

//do something special with the last value here before you process all the others?
echo "Last is $lastValue", "\n";

foreach ($array as $key => $value) {
    //do something with all values before the last value
    echo "All except last value: $value", "\n";
}

//do something special with the last value here after you process all the others?
echo "Last is $lastValue", "\n";

回答你最初的问题:"在我构建查询时追加和/或参数",这将循环遍历所有值,然后将它们连接成一个字符串,其中每个值之间用 "and" 分隔,但不会在第一个值之前或最后一个值之后添加分隔符:

$params = [];
foreach ($array as $value) {
    $params[] = doSomething($value);
}
$parameters = implode(" and ", $params);

2
当然,它将在每次迭代中执行--$toEnd,这就是重点。如果我把它移到循环外面,它就不会再起作用了。 - OIS
最简单的方法之一。$lastValue = array_pop($array); 谢谢。 - Elias Nicolas

26

从 PHP 7.3 开始:

您可以使用 array_key_last($array) 获取数组的最后一个键的值,并将其与当前键进行比较:

$last_key = array_key_last($array);
foreach ($array as $key => $value) {
    if ($key == $last_key) {
        // last element
    } else {
        // not last element
    }
}

25

一种方法是检测迭代器是否具有next。如果迭代器没有下一个元素,那么意味着你已经到了最后一次循环。

foreach ($some_array as $element) {
    if(!next($some_array)) {
         // This is the last $element
    }
}

3
无法在PHP 7+中使用,因为“在PHP 7中,foreach不再使用内部数组指针”。 - Damien Debin
@DamienDebin 你在PHP7中测试过吗?它对我有效。我不明白为什么foreach不使用内部数组指针会有什么影响。next()确实使用并推进了内部数组指针,并且在最后一个元素检查时将返回false。我唯一看到的问题是falsey值会触发最后一个元素检查。 - Cave Johnson

23

已经有很多答案了,但是也值得研究迭代器,特别是因为它被要求使用标准方法:

$arr = range(1, 3);

$it = new CachingIterator(new ArrayIterator($arr));
foreach($it as $key => $value)
{
  if (!$it->hasNext()) echo 'Last:';
  echo $value, "\n";
}

你可能会发现其他情况下有更加灵活的解决方案。


很棒的回答。我很欣赏你使用了编程语言中为此任务而设计的特性。在像PHP这样的脚本语言中,i=0;++i;似乎总是有些不正规。 - CheddarMonkey

15

从 foreach 数组中获取第一个和最后一个元素

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

    if ($value === end($array)) {
        echo 'LAST ITEM!';
    }
}

1
这似乎非常慢,因为您总是调用两个函数来获取比较值。 - Dwza

8
因此,如果您的数组具有唯一的数组值,则确定最后一次迭代是微不足道的:
foreach($array as $element) {
    if ($element === end($array))
        echo 'LAST ELEMENT!';
}

正如您所看到的,如果数组中最后一个元素只出现一次,则此方法可行,否则会误报。如果不是这样,您需要比较键(这些键肯定是唯一的)。

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

此外请注意严格比较运算符,这在这种情况下非常重要。

这是一种相当低效的方式。 - Your Common Sense
不是的。end()执行O(1)。它也比其他解决方案更短,并且读起来很好 -> 如果元素等于数组的末尾,则写入“Last”。 - Rok Kralj
这比我前面和后面的例子慢了两倍以上,针对100000个值。 - OIS

8

不要在最后一个值后面添加逗号:

数组:

$data = ['lorem', 'ipsum', 'dolor', 'sit', 'amet'];

这个函数:

$result = "";
foreach($data as $value) {
    $resut .= (next($data)) ? "$value, " : $value;
}

结果:

print $result;

lorem, ipsum, dolor, sit, amet


1
它在PHP7+上完美运行。 - mfkocak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接