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

Posted

技术标签:

【中文标题】在 PHP 中使用 foreach 循环时查找数组的最后一个元素【英文标题】:Find the last element of an array while using a foreach loop in PHP 【发布时间】:2010-10-14 11:43:16 【问题描述】:

我正在使用一些参数编写 SQL 查询创建器。在 Java 中,只需检查当前数组位置和数组长度,就可以很容易地从 for 循环中检测到数组的最后一个元素。

for(int i=0; i< arr.length;i++)
     boolean isLastElem = i== (arr.length -1) ? true : false;        

php 中,它们具有访问数组的非整数索引。因此,您必须使用 foreach 循环遍历数组。当您需要做出一些决定(在我的情况下,在构建查询时附加或/和参数)时,这会成为问题。

我确信必须有一些标准的方法来做到这一点。

你如何在 PHP 中解决这个问题?

【问题讨论】:

您是否要确定是否应该在 where 子句的各个部分之间连接“AND”或“OR”? 只是指出您应该将总数存储在一个变量中,而不是为每次迭代调用一个方法。 for(int i=0, int t = arr.length; i ***.com/questions/156650/… 看看这个解决方案:***.com/a/29474468/1478566 使用 end(array) use simmilar answers 【参考方案1】:

你可以做一个 count()。

for ($i=0;$i<count(arr);$i++)
    $i == count(arr)-1 ? true : false;

或者如果你只寻找最后一个元素,你可以使用 end()。

end(arr);

只返回最后一个元素。

而且,事实证明,您可以按整数索引 php 数组。非常满意

arr[1];

【讨论】:

end(arr) 的缺点是它将数组的内部指针设置为最后一个元素.. 不,你不应该使用整数来访问数组,除非你知道键是数字和顺序的。考虑:$a = array(0=&gt;'A', 2=&gt;'B', 'aaa'=&gt;'C')。访问$a[count($a)-1]会得到什么?【参考方案2】:

听起来你想要这样的东西:

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

话虽如此,您不必在 php.ini 中使用 foreach 遍历“数组”。

【讨论】:

我想我会选择这个解决方案,因为它与我发布的代码几乎相似。即使是杰里米的答案也很合适,但我认为与这个答案相比,它并没有那么复杂。我没有进行任何测试,但我想这个答案会更快,因为它没有提取键数组。这应该有 O(1) 速度 $numItems = count($arr) 技巧是不需要的并且会降低可读性 - 在 PHP 中,每次访问 count($arr) 都不会降低性能。原因是项目计数在内部保存为数组标题中的特殊字段,并且不是即时计算的。这个技巧来自其他语言(C、Java?...)。 这很有趣@johndodo,每次访问 count($arr) 都没有性能损失。您是否有任何链接/来源可以记录此特定优化?谢谢! 很遗憾,在 PHP 中这个问题的最正确的解决方案看起来相当不优雅:( @tomsihap $i 需要在循环内递增,与数组迭代同步。 $i 需要表示数组中项的编号,以便可以用来确定何时到达最后一项。如果没有 ++,循环只会将“0”与项目总数进行比较。【参考方案3】:

您可以使用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
    

【讨论】:

+1 我同意 - 其他解决方案依赖于具有数字索引的数组。 在我自己的辩护中,我的答案不依赖于具有数字键的数组:) 字符串比较比整数慢,并且在比较字符串和整数时并不总是准确(你至少应该使用 ===)。我对此投了反对票。 它很优雅,但会引起严格注意,因为“end”需要一个参考值:( 修复严格通知:$lastKey = array_search(end($array), $array);【参考方案4】:

您仍然可以将该方法与关联数组一起使用:

$keys = array_keys($array);
for ($i = 0, $l = count($array); $i < $l; ++$i) 
    $key = $array[$i];
    $value = $array[$key];
    $isLastItem = ($i == ($l - 1));
    // do stuff


// or this way...

$i = 0;
$l = count($array);
foreach ($array as $key => $value) 
    $isLastItem = ($i == ($l - 1));
    // do stuff
    ++$i;

【讨论】:

请更改 $key = $array[$i];到 $key = $keys[$i];在第一个 for 循环中。【参考方案5】:

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

并回答您最初的问题“在我的情况下,在构建查询时附加或/和参数”;这将遍历所有值,然后将它们连接到一个字符串中,它们之间有“和”,但不是在第一个值之前或最后一个值之后:

$params = [];
foreach ($array as $value) 
    $params[] = doSomething($value);

$parameters = implode(" and ", $params);

【讨论】:

当然它会为每次迭代执行 --$toEnd ,这就是重点。如果我把它移到循环之外,它就不再起作用了。 最简单的方法。 $lastValue = array_pop($array); 谢谢。【参考方案6】:

你也可以这样做:

end( $elements );
$endKey = key($elements);
foreach ($elements as $key => $value)

     if ($key == $endKey) // -- this is the last item
     
          // do something
     

     // more code

【讨论】:

end 返回值而不是数组,因此您制作它的方式不起作用。字符串比较也比整数慢。 你是对的。它应该是 end($elements); $endKey = key($elements);【参考方案7】:

这是另一种方法:

$arr = range(1, 10);

$end = end($arr);
reset($arr);

while( list($k, $v) = each($arr) )

    if( $n == $end )
    
        echo 'last!';
    
    else
    
        echo sprintf('%s ', $v);
    

【讨论】:

【参考方案8】:

注意:这不起作用,因为调用 next() 会推进数组指针,因此您将跳过循环中的所有其他元素


为什么这么复杂?

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

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

【讨论】:

如果下一个 $input 包含一个布尔值 false,则不会,这是 next() 的一个主要问题。 除非我弄错了,否则这不起作用,因为调用 next() 会推进数组指针,因此您会跳过循环中的所有其他元素。 似乎对我不起作用。倒数第二个元素没有逗号,但应该。 如果该值等于 bool false 它不起作用。也不打印倒数第二个和最后一个值之间的最后一个逗号。 对于任何想在 PHP7 中使用它的人的注意事项 - 数组指针不会在 foreach 循环中移动,这将不起作用。【参考方案9】:

如果您需要对除第一个或最后一个元素之外的每个元素执行某些操作,并且仅当数组中有多个元素时,我更喜欢以下解决方案。

我知道上面有很多解决方案,并且比我早几个月/一年发布,但我觉得这本身就相当优雅。检查每个循环也是布尔检查,而不是数字“i=(count-1)”检查,这可能会减少开销。

循环的结构可能会让人觉得别扭,但你可以将其与 html 表格标签中的 thead(开始)、tfoot(结束)、tbody(当前)的顺序进行比较。

$first = true;
foreach($array as $key => $value) 
    if ($first) 
        $first = false;
        // Do what you want to do before the first element
        echo "List of key, value pairs:\n";
     else 
        // Do what you want to do at the end of every element
        // except the last, assuming the list has more than one element
        echo "\n";
    
    // Do what you want to do for the current element
    echo $key . ' => ' . $value;

例如,在 Web 开发方面,如果您想为无序列表 (ul) 中除最后一个 之外的每个元素添加 border-bottom,那么您可以添加一个 除了第一个元素之外的每个元素的border-top(IE7+ 和Firefox/Webkit 支持的CSS :first-child 支持此逻辑,而IE7 不支持:last-child)。

您也可以随意为每个嵌套循环重用 $first 变量,并且一切都会正常工作,因为在第一次迭代的第一个过程中每个循环都会使 $first 为假(因此中断/异常不会导致问题)。

$first = true;
foreach($array as $key => $subArray) 
    if ($first) 
        $string = "List of key => value array pairs:\n";
        $first = false;
     else 
        echo "\n";
    

    $string .= $key . '=>(';
    $first = true;
    foreach($subArray as $key => $value) 
        if ($first) 
            $first = false;
         else 
            $string .= ', ';
        
        $string .= $key . '=>' . $value;
    
    $string .= ')';

echo $string;

示例输出:

List of key => value array pairs:
key1=>(v1_key1=>v1_val1, v1_key2=>v1_val2)
key2=>(v2_key1=>v2_val1, v2_key2=>v2_val2, v2_key3=>v2_val3)
key3=>(v3_key1=>v3_val1)

【讨论】:

谢谢,这是我最喜欢的解决方案!它非常灵活,只需一个布尔值。顺便说一句,我认为这也适用于包含至少一个元素的数组(不仅超过一个元素)。【参考方案10】:

如果我理解你的意思,那么你只需要反转数组并通过 pop 命令获取最后一个元素:

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);

【讨论】:

【参考方案11】:

如何使用“结束”? http://php.net/manual/en/function.end.php

【讨论】:

【参考方案12】:

您也可以尝试使用此方法进行查询...此处显示为 INSERT

<?php
 $week=array('one'=>'monday','two'=>'tuesday','three'=>'wednesday','four'=>'thursday','five'=>'friday','six'=>'saturday','seven'=>'sunday');
 $keys = array_keys($week);
 $string = "INSERT INTO my_table ('";
 $string .= implode("','", $keys);
 $string .= "') VALUES ('";
 $string .= implode("','", $week);
 $string .= "');";
 echo $string;
?>

【讨论】:

【参考方案13】:

对于 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 毫秒

【讨论】:

【参考方案14】:

听起来你想要这样的东西:

$array = array(
    'First',
    'Second',
    'Third',
    'Last'
);

foreach($array as $key => $value)

    if(end($array) === $value)
    
       echo "last index!" . $value;
    

【讨论】:

使用该值通常不是一个好主意,因为如果数组有两个相同的值,它将无法正常工作。【参考方案15】:

已经有很多答案了,但也值得研究一下迭代器,尤其是当它被要求提供一种标准方式时:

$arr = range(1, 3);

$it = new CachingIterator(new ArrayIterator($arr));
foreach($it as $key => $value)

  if (!$it->hasNext()) echo 'Last:';
  echo $value, "\n";

您可能会发现某些东西在其他情况下也更灵活。

【讨论】:

很好的答案。我很欣赏您正在使用用于该任务的语言功能。 i=0;++i; 在 PHP 之类的脚本语言中总是看起来很老套。【参考方案16】:

另一种方法是记住前一个循环循环的结果并将其用作最终结果:

    $result = $where = "";
    foreach ($conditions as $col => $val) 
        $result = $where .= $this->getAdapter()->quoteInto($col.' = ?', $val);
        $where .=  " AND ";
    
    return $this->delete($result);

【讨论】:

【参考方案17】:

我个人使用这种结构,可以轻松使用 html

和 元素:只需更改其他属性的相等性...

该数组不能包含假项目,但所有其他项目都被强制转换为假布尔值。

$table = array( 'a' , 'b', 'c');
$it = reset($table);
while( $it !== false ) 
    echo 'all loops';echo $it;
    $nextIt = next($table);
    if ($nextIt === false || $nextIt === $it) 
            echo 'last loop or two identical items';
    
    $it = $nextIt;

【讨论】:

【参考方案18】:

因此,如果您的数组具有唯一的数组值,那么确定最后一次迭代是微不足道的:

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!';

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

【讨论】:

这种方式效率很低。 不。它不是。 end() 执行 O(1)。它也比其他解决方案更短,并且读起来很好 -> 如果元素等于数组的末尾,请写“Last”。 对于 100000 个值,这比我的第一个和最后一个示例慢两倍以上。【参考方案19】:

我有一种强烈的感觉,在这个“XY 问题”的根源上,OP 只需要 implode() 函数。

【讨论】:

真的。但在某些情况下,内爆并不那么实用。想象一下,例如试图内爆一长串包含大量动态变量的 html。当然,您可以对其执行 ob_start/ob_get_clean,或者将其构建为 $str ='...'。但是,有时这可能被认为有点矫枉过正【参考方案20】:

您可以通过以下方式直接获取最后一个索引:

$numItems = count($arr);

echo $arr[$numItems-1];

【讨论】:

【参考方案21】:

假设您将数组存储在变量中...

foreach($array as $key=>$value) 
 
    echo $value;
    if($key != count($array)-1)  echo ", "; 

【讨论】:

这个非常简单实用。我只会在 foreach 循环之外先对数组进行计数,这样程序就不必在每次 foreach 函数评估每个项目时都进行计数。 这不适用于关联数组。 $key 并不总是一个数字。 你也可以试试echo implode(",", $array)【参考方案22】:
<?php foreach($have_comments as $key => $page_comment): ?>
    <?php echo $page_comment;?>
    <?php if($key+1<count($have_comments)): ?> 
        <?php echo ', '; ?>
    <?php endif;?>
<?php endforeach;?>

【讨论】:

【参考方案23】:

因为您查找 EOF 数组的目的只是为了粘合。了解以下策略。您不需要 EOF:

$given_array = array('column1'=>'value1',
                     'column2'=>'value2',
                     'column3'=>'value3');

$glue = '';
foreach($given_array as $column_name=>$value)
    $where .= " $glue $column_name = $value"; //appending the glue
    $glue   = 'AND';

echo $where;

o/p:

column1 = value1 AND column2 = value2 AND column3 = value3

【讨论】:

【参考方案24】:

我有点喜欢以下内容,因为我觉得它相当整洁。假设我们正在创建一个在所有元素之间带有分隔符的字符串:例如a,b,c

$first = true;
foreach ( $items as $item ) 
    $str = ($first)?$first=false:", ".$item;

【讨论】:

在不声明 $first; 的情况下让它更简单;使用 foreach ( $items as $key=>$item ) 然后 $str = ($key==0)?【参考方案25】:

这应该是找到最后一个元素的简单方法:

foreach ( $array as $key => $a ) 
    if ( end( array_keys( $array ) ) == $key ) 
        echo "Last element";
      else 
        echo "Just another element";
     
  

参考:Link

【讨论】:

- 链接断开-【参考方案26】:

这是我的解决方案: 只需获取数组的计数,减 1(因为它们从 0 开始)。

$lastkey = count($array) - 1;
foreach($array as $k=>$a)
    if($k==$lastkey)
        /*do something*/
    

【讨论】:

【参考方案27】:

一种方法是检测迭代器是否有next。如果没有 next 连接到迭代器,则表示您处于最后一个循环中。

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

【讨论】:

不适用于 PHP 7+,因为“在 PHP 7 中,foreach 不使用内部数组指针。”。【参考方案28】:
foreach ($array as $key => $value) 

  $class = ( $key !== count( $array ) -1 ) ? " class='not-last'" : " class='last'";

  echo "<div$class>";
  echo "$value['the_title']";
  echo "</div>";


Reference

【讨论】:

【参考方案29】:

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

数组:

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

功能:

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

结果:

print $result;

lorem、ipsum、dolor、sit、amet

【讨论】:

【参考方案30】:

试试这个简单的解决方案

$test = ['a' => 1, 'b' => 2, 'c' => 3];

$last_array_value = end($test);

foreach ($test as $key => $value) 
   if ($value === $last_array_value) 
      echo $value; // display the last value  
    else 
     echo $value; // display the values that are not last elements 
   

【讨论】:

以上是关于在 PHP 中使用 foreach 循环时查找数组的最后一个元素的主要内容,如果未能解决你的问题,请参考以下文章

使用PHP与2个foreach循环中的数组进行比较时如何获取迭代次数

PHP中使用foreach循环读取数组数据的方法

PHP中如何使用foreach结构遍历数组?

php中foreach循环遍历二维数组

PHP中使用foreach循环读取数组数据的方法

如何在 PHP/Eclipse 中对 foreach 循环中从数组中拉出的自定义对象进行智能感知?