ChatGPT解决这个技术问题 Extra ChatGPT

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

我正在使用一些参数编写 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
看看这个解决方案:stackoverflow.com/a/29474468/1478566
使用结束(数组)use simmilar answers

h
hakre

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

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

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


$numItems = count($arr) 技巧是不需要的,它会降低可读性 - 在 PHP 中,每次访问 count($arr) 都不会造成性能损失。原因是项目计数在内部保存为数组标题中的特殊字段,并且不是即时计算的。这个技巧来自其他语言(C,Java?,...)。
这很有趣@johndodo,每次访问 count($arr) 都没有性能损失。您是否有任何链接/来源可以记录此特定优化?谢谢!
可悲的是,在 PHP 中,这个问题的最正确解决方案看起来相当不优雅:(
@tomsihap $i 需要在循环内递增,与数组迭代同步。 $i 需要表示数组中项的编号,以便可以用来确定何时到达最后一项。如果没有 ++,循环只会将“0”与项目总数进行比较。
自 PHP 7.3 到现在您可以使用 array_key_last($array) 获取数组的最后一个键的值
P
Paige Ruten

您可以使用 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);
P
PiTheNumber

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

为什么这么复杂?

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

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


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

当 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); 谢谢。
h
hakre

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

$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 之类的脚本语言中似乎总是很老套。
R
Raheel

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

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

不适用于 PHP 7+,因为“在 PHP 7 中,foreach 不使用内部数组指针。”。
T
TechDogLover OR kiaNasirzadeh

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

D
Darkcoder

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

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

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

这个接缝很慢,因为你总是调用 2 函数来获取比较值
R
Rok Kralj

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

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 个值的示例慢两倍多。
n
nickf

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

$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 循环中。
M
Martin Heisterkamp

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

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

这是非常简单和有用的。我只会在 foreach 循环之外先对数组进行计数,这样程序就不必在每次 foreach 函数评估每个项目时都进行计数。
这不适用于关联数组。 $key 并不总是一个数字。
您也可以尝试使用 echo implode(",", $array)
V
Visavì

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

数组:

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

功能:

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

结果:

print $result;

lorem, ipsum, dolor, 坐, amet


A
Ankit Aggarwal

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

我知道上面有很多解决方案,并且比我早几个月/一年发布,但我觉得这本身就相当优雅。检查每个循环也是一个布尔检查,而不是数字“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 支持的 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)

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

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

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

参考:Link


- 断开的链接 -
Y
Your Common Sense

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


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

因为您寻找 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

Ç
Çağ

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


A
Ashique CM

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

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

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

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

你可以做一个计数()。

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

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

end(arr);

只返回最后一个元素。

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

arr[1];

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

你也可以这样做:

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);
A
Alastair Brayne

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

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

在不声明 $first 的情况下使其更简单;使用 foreach ( $items as $key=>$item ) 然后 $str = ($key==0)?
I
ITWitch

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

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

A
Ayman Elshehawy
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


J
Justin Vincent

如果它是一维数组,您可以这样做以保持简短和甜蜜:

foreach($items as $idx => $item) {
    if (!isset($items[$idx+1])) {
        print "I am last";
    }
}

F
FsCode
$array  = array("dog", "rabbit", "horse", "rat", "cat");
foreach($array as $index => $animal) {
    if ($index === array_key_first($array))
        echo $animal; // output: dog

    if ($index === array_key_last($array))
        echo $animal; // output: cat
}

K
Kevin

这是另一种方法:

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

这个答案缺少它的教育解释。 echo sprintf() 是一种“反模式”。绝对没有任何理由让任何人出于任何原因在任何代码中编写 echo sprintf() —— 每次都应该是 printf()。
J
James

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

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);

M
Mark

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

M
Morg.

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


L
Leven

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

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