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


215

我正在使用一些参数编写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 =长度; i <t; i ++)。
OIS,2009年



Answers:


313

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

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

话虽这么说,您不必-遍历foreachphp中使用的“数组” 。


我想我会选择这种解决方案,因为它几乎与我发布的代码相似。甚至杰里米(Jeremy)的答案也很合适,但与该答案相比,我认为它并没有什么复杂性。我没有进行任何测试,但是我猜这个答案会更快,因为它没有提取键数组。这应该具有O(1)速度
Vaibhav Kamble 2009年

18
$numItems = count($arr)不需要技巧,并且会降低可读性-在PHP中,每次访问count($ arr)都不会降低性能。原因是项目计数在内部保存为数组标题中的特殊字段,而不是即时计算的。这个技巧来自其他语言(C,Java?,...)。
johndodo 2011年

7
@johndodo很有意思,每次访问count($ arr)都不会降低性能。您是否有任何链接/来源记录了此特定优化所在?谢谢!
zuallauz 2012年

2
令人遗憾的是,在PHP中,针对此问题的最正确解决方案看起来不太优雅:(
kizzx2 2013年

1
@tomsihap $ i需要在循环内与数组迭代一起增加。$ i需要表示数组中该项的编号,以便可以用来确定何时到达最后一项。没有++,循环将只能将“ 0”与项目总数进行比较。
鲍比·杰克

201

您可以使用来获取数组最后一个键的值,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
    }
}

2
+1我同意-其他解决方案依赖于具有数字索引的数组。
2009年

19
在我自己的辩护中,我的答案并不依赖于具有数字键的数组:)
Richard Levasseur

2
字符串比较慢于整数,并且在将字符串与整数进行比较时并不总是准确的(您至少应该使用===)。我对此表示反对。
OIS,2009年

4
它很优雅,但会发出“严格通知”,因为“ end”需要参考值:(
Wiliam 2012年

10
修复严格通知:$lastKey = array_search(end($array), $array);
Ajax

44

为什么这么复杂?

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

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


2
如果下一个$ input包含布尔值false,则不是这样,这是next()的主要问题。
soulseekah

29
除非我弄错了,否则这是行不通的,因为调用next()会使数组指针前进,因此您将跳过循环中的所有其他元素。
约旦列夫

2
似乎不适合我。倒数第二个元素没有逗号,但是应该。
zuallauz 2012年

1
如果该值等于布尔值false,则不起作用。也不会打印倒数第二个和最后一个值之间的最后一个逗号。
OIS,2015年

1
任何想在PHP7中使用它的人的注释-数组指针不会在foreach循环中移动,因此将不起作用。
Scott Flack

26

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

2
当然,它将在每次迭代中执行-$ toEnd,这就是重点。如果我将其移出循环,它将不再起作用。
OIS,2009年

有史以来最简单的方法。$lastValue = array_pop($array);谢谢。
Elias Nicolas

21

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

$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这样的脚本语言中总是显得有些黑。
CheddarMonkey

15

一种方法是检测迭代器是否具有next。如果没有附加到迭代器的下一个对象,则意味着您处于最后一个循环中。

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

我认为这是最简单的方法,需要最少的代码!
hi im zvaehn

1
不适用于PHP 7+,因为“在PHP 7中,foreach不使用内部数组指针。”。
Damien Debin

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

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


这是非常低效的方式。
您的常识

不。它不是。end()执行O(1)。它也比其他解决方案要短,并且读取效果很好->如果element等于数组的末尾,则写“ Last”。
Rok Kralj

这是我的第一个和最后一个100000值示例的速度的两倍以上。
OIS 2015年

5

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

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

这是非常简单和有用的。我只会先在foreach循环之外对数组进行计数,以使程序不必在每次foreach函数评估每个项目时都进行计数。
Pathros

3
这不适用于关联数组。$ key并不总是数字。
乔纳森(Jonathan)

5

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

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

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

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

1
请更改$ key = $ array [$ i]; 到$ key = $ keys [$ i]; 在第一个for循环中。
Narek'3

4

如果您需要为除第一个或最后一个元素之外的每个元素做某事,并且仅当数组中有多个元素时,我才喜欢以下解决方案。

我知道上面有很多解决方案,而且比我的发布早了数月/一年,但是我觉得这很不错。与数字“ 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)中除最后一个元素之外的每个元素上添加边框底,那么您可以为除第一个元素之外的每个元素(CSS: IE7 +和Firefox / Webkit支持的第一个孩子支持此逻辑,而IE7不支持:last-child。

您可以随时为每个嵌套循环重用$ first变量,并且事情将正常进行,因为在第一次迭代的第一个过程中每个循环都会使$ first为false(因此,中断/异常不会导致问题) 。

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

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


3

我有一种强烈的感觉,就是在这个“ XY问题”的根源上,OP只是想implode()发挥作用。


1
真正。在某些情况下,内爆并不那么实用。试想一下,例如,尝试内嵌包含大量动态变量的html长字符串。当然,您可以对其进行ob_start / ob_get_clean,或仅将其构建为$ str ='...'。但是,有些时候,这可以被视为只是一点点矫枉过正
阿拉斯泰尔·布雷恩

3

因为您想要找到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


2

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

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

foreach($array as $key => $value)
{
    if(end($array) === $value)
    {
       echo "last index!" . $value;
    }
}

2
通常,使用该值不是一个好主意,因为如果数组具有两个相同的值,它将无法正常工作。
2014年

2

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

数组:

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

功能:

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

结果:

print $result;

lorem,ipsum,dolor,坐,amet


1

您可以做一个count()。

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

或者,如果仅查找最后一个元素,则可以使用end()。

end(arr);

仅返回最后一个元素。

事实证明,您可以按整数索引php数组。很高兴

arr[1];

1
end(arr)的缺点是它将数组的内部指针设置为最后一个元素
。– Vijay

不,除非您知道键是数字键和顺序键,否则不应使用整数来访问数组。考虑:$a = array(0=>'A', 2=>'B', 'aaa'=>'C')。访问后会得到什么$a[count($a)-1]
johndodo 2011年

1

您还可以执行以下操作:

end( $elements );
$endKey = key($elements);
foreach ($elements as $key => $value)
{
     if ($key == $endKey) // -- this is the last item
     {
          // do something
     }

     // more code
}

end返回的值不是数组,因此您使用它的方式无效。字符串比较也比整数慢。
OIS,2009年

你是对的。它应该是end($ elements); $ endKey =键($ elements);
KOGI

1

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

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

使它更简单而无需声明$ first;使用foreach($ items as $ key => $ item)然后$ str =($ key == 0)吗?
米兰Rilex Ristic


0

这是您可以执行的另一种方法:

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

0

如果我了解您,那么您所需要做的就是反转数组并通过pop命令获取最后一个元素:

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);

0

您也可以尝试使用此方法进行查询...此处显示为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;
?>

0

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


0

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

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

0

我个人使用这种构造,可以轻松使用html <ul>和<li>元素:只需更改其他属性的相等性即可...

数组不能包含错误的项目,但所有其他项目都将转换为错误的布尔值。

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


0
<?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;?>

0

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

$lastkey = count($array) - 1;
foreach($array as $k=>$a){
    if($k==$lastkey){
        /*do something*/
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.