Encuentra el último elemento de un array mientras usas un bucle foreach en PHP


Estoy escribiendo un creador de consultas SQL usando algunos parámetros. En Java, es muy fácil detectar el último elemento de una matriz desde el interior del bucle for simplemente comprobando la posición actual de la matriz con la longitud de la matriz.

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

En PHP tienen índices no enteros para acceder a matrices. Por lo tanto, debe iterar sobre una matriz utilizando un bucle foreach. Esto se vuelve problemático cuando necesita tomar alguna decisión (en mi caso para anexar o/y parámetro mientras se construye la consulta).

Estoy seguro debe haber alguna forma estándar de hacer esto.

¿Cómo se resuelve esto en PHP?

 177
Author: Thamilan, 2009-03-20

29 answers

Parece que quieres algo como esto:

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

Dicho esto, no tienes que iterar sobre un "array" usando foreach en php.

 262
Author: Richard Levasseur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-10 22:01:40

Puede obtener el valor de la última clave del array usando end(array_keys($array)) y compararlo con la clave actual:

$last_key = end(array_keys($array));
foreach ($array as $key => $value) {
    if ($key == $last_key) {
        // last element
    } else {
        // not last element
    }
}
 177
Author: Jeremy Ruten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-20 06:07:08

¿Por qué tan complicado?

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

Esto agregará un, detrás de cada valor excepto el último!

 36
Author: Trikks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-14 14:52:04

Cuando toEnd alcanza 0 significa que está en la última iteración del bucle.

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

El último valor todavía está disponible después del bucle, por lo que si solo desea usarlo para más cosas después del bucle, esto es mejor:

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

Si no desea tratar el último valor como bucles internos especiales. Esto debería ser más rápido si tiene matrices grandes. (Si reutiliza la matriz después del bucle dentro del mismo ámbito, primero tiene que "copiar" la matriz).

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

Y para responder a su pregunta original "en mi caso para anexar el parámetro or / and mientras se construye la consulta" ; esto hará un bucle sobre todos los valores, luego los unirá a una cadena con " y " entre ellos, pero no antes del primer valor o después del último valor:

$params = [];
foreach ($array as $value) {
    $params[] = doSomething($value);
}
$parameters = implode(" and ", $params);
 21
Author: OIS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-26 15:40:09

Ya hay muchas respuestas, pero vale la pena mirar en los iteradores también, especialmente porque se ha pedido una forma estándar:

$arr = range(1, 3);

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

Usted podría encontrar algo que funciona más flexible para otros casos, también.

 19
Author: hakre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-11 01:25:05

Por lo tanto, si su matriz tiene valores de matriz únicos, entonces determinar la última iteración es trivial:

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

Como puede ver, esto funciona si el último elemento aparece solo una vez en la matriz, de lo contrario se obtiene una falsa alarma. En él no es, usted tiene que comparar las claves (que son únicos con seguridad).

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

También tenga en cuenta el operador de coparisión estricta, que es bastante importante en este caso.

 7
Author: Rok Kralj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-21 07:11:59

Asumiendo que tiene el array almacenado en una variable...

foreach($array as $key=>$value) 
{ 
    echo $value;
    if($key != count($array)-1) { echo ", "; }
}
 5
Author: Martin Heisterkamp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-09 11:38:27

Una forma podría ser detectar si el iterador tiene next. Si no hay next conectado al iterador significa que estás en el último bucle.

foreach ($some_array as $element) {
    if(!next($some_array)) {
         // This is the last $element
    }
}
 5
Author: Raheel Khan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-18 16:37:42

Si necesitas hacer algo para cada elemento, excepto el primero o el último y sólo si hay más de un elemento en la matriz, prefiero la siguiente solución.

Sé que hay muchas soluciones anteriores y publicadas meses/un año antes de la mía, pero esto es algo que siento que es bastante elegante en sí mismo. La comprobación de cada bucle es también una comprobación booleana en lugar de una comprobación numérica " i = (count-1)", que puede permitir menos sobrecarga.

La estructura del bucle puede siéntase incómodo, pero puede compararlo con el orden de thead (principio), tfoot (final), tbody (actual) en las etiquetas de tabla HTML.

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

Por ejemplo, en términos de desarrollo web, si desea agregar un border-bottom a cada elemento excepto el último en una lista desordenada (ul), entonces puede agregar un border-top a cada elemento excepto el primero (el CSS: first-child, soportado por IE7 + y Firefox / Webkit soporta esta lógica, mientras que: last-child no es soportado por IE7).

Puede sentirse libre de reutilizar la variable $first para todos y cada bucle anidado también y las cosas funcionarán bien ya que cada bucle hace false first false durante el primer proceso de la primera iteración (por lo que las interrupciones/excepciones no causarán problemas).

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

Ejemplo de salida:

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)
 4
Author: Ankit Aggarwal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-26 15:56:34

Esta debería ser la manera fácil de encontrar el último elemento:

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

Referencia: Enlace

 4
Author: Duli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-22 10:42:32

Todavía puede usar ese método con matrices asociativas:

$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;
}
 3
Author: nickf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-20 06:54:57

Tengo la fuerte sensación de que en la raíz de este "problema XY" el OP quería solo la función implode().

 3
Author: Your Common Sense,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-21 07:22:18

Como su intención de encontrar la matriz EOF es solo para el pegamento. Obtener introducido a la táctica de abajo. Usted no necesita requerir el 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
 3
Author: Angelin Nadar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-06 05:36:39

Parece que quieres algo como esto:

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

foreach($array as $key => $value)
{
    if(end($array) === $value)
    {
       echo "last index!" . $value;
    }
}
 2
Author: Ashique CM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-22 06:47:13

Puedes hacer un count().

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

O si estás buscando SOLO el último elemento, puedes usar end().

end(arr);

Devuelve solo el último elemento.

Y, como resulta, puede indexar arrays php por enteros. Es perfectamente feliz con

arr[1];
 1
Author: helloandre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-20 06:05:26
 1
Author: Çağ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-08 13:48:07

También podrías hacer algo como esto:

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

     // more code
}
 1
Author: KOGI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-28 20:17:36

Me gusta un poco lo siguiente, ya que siento que es bastante limpio. Supongamos que estamos creando una cadena con separadores entre todos los elementos: por ejemplo,a,b, c

$first = true;
foreach ( $items as $item ) {
    $str = ($first)?$first=false:", ".$item;
}
 1
Author: Alastair Brayne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-16 17:28:16

Aquí hay otra forma de hacerlo:

$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
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-09 23:52:31

Si te entiendo, entonces todo lo que necesitas es invertir la matriz y obtener el último elemento mediante un comando pop:

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);
 0
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-08 16:13:41

También puedes probar esto para hacer tu consulta... se muestra aquí con 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
Author: Mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 20:27:45

Para scripts de generación de consultas SQL, o cualquier cosa que realice una acción diferente para el primer o último elemento, es mucho más rápido (casi el doble de rápido) evitar el uso de comprobaciones de variables innecesarias.

La solución aceptada actual utiliza un bucle y una comprobación dentro del bucle que se realizará cada [s] sole_iteración, la forma correcta (rápida) de hacer esto es la siguiente:

$numItems = count($arr);
$i=0;
$firstitem=$arr[0];
$i++;
while($i<$numItems-1){
    $some_item=$arr[$i];
    $i++;
}
$last_item=$arr[$i];
$i++;

Un pequeño benchmark casero mostró lo siguiente:

Test1: 100000 corridas de modelo morg

Tiempo: 1869.3430423737 milisegundos

Test2: 100000 corridas del modelo si el último

Tiempo: 3235.6359958649 milisegundos

 0
Author: Morg.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-09 13:29:14

Otra forma de hacerlo es recordar el resultado del ciclo de bucle anterior y usarlo como resultado final:

    $result = $where = "";
    foreach ($conditions as $col => $val) {
        $result = $where .= $this->getAdapter()->quoteInto($col.' = ?', $val);
        $where .=  " AND ";
    }
    return $this->delete($result);
 0
Author: Leven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-11 21:52:28

Personalmente uso este tipo de construcción que permite un uso fácil con elementos html y : simplemente cambie la igualdad por otra propiedad...

El array no puede contener elementos false sino todos los demás elementos que se vierten en el booleano false.

$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
Author: MUY Belgium,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-30 11:34:00

Puedes obtener el último índice de la siguiente manera:

$numItems = count($arr);

echo $arr[$numItems-1];

 0
Author: Denis Omeri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-16 13:59:23
<?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
Author: Zarpele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-21 14:19:01

Aquí está mi solución: Simplemente obtenga la cuenta de su matriz, menos 1 (ya que comienzan en 0).

$lastkey = count($array) - 1;
foreach($array as $k=>$a){
    if($k==$lastkey){
        /*do something*/
    }
}
 0
Author: ITWitch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-22 08:04:38
foreach ($array as $key => $value) {

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

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

}

Referencia

 0
Author: Ayman Elshehawy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-23 13:10:17

Tengo una solución generalizada que uso, con el propósito común de compilar una cadena a partir de una matriz de valores de cadena. Todo lo que hago es añadir una cadena inusual al final y luego reemplazarlo.

Función para devolver una cadena de una matriz, separada, sin separador final:

function returnArraySeparated($aArr, $sSep, $sAdd = "@X@") {

$strReturn = (string) "";


# Compile the set:
foreach ($aArr as $sItem) {
    $strReturn .= $sItem . $sSep;
}

# Easy strip the end:
$strReturn = str_replace($sSep . $sAdd, "", $strReturn . $sAdd);

return $strReturn;
}

Nada especial, pero funciona :)

 -3
Author: Rich Harding,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-19 20:47:09