Respuestas:
Podrías usar un contador:
$i = 0;
$len = count($array);
foreach ($array as $item) {
if ($i == 0) {
// first
} else if ($i == $len - 1) {
// last
}
// …
$i++;
}
$i = 1
, no tiene que preocuparse $len - 1
, solo use $len
.
Si prefiere una solución que no requiera la inicialización del contador fuera del ciclo, propongo comparar la clave de iteración actual con la función que le indica la última / primera clave de la matriz.
Esto se vuelve algo más eficiente (y más legible) con el próximo PHP 7.3.
foreach($array as $key => $element) {
if ($key === array_key_first($array))
echo 'FIRST ELEMENT!';
if ($key === array_key_last($array))
echo 'LAST ELEMENT!';
}
foreach($array as $key => $element) {
reset($array);
if ($key === key($array))
echo 'FIRST ELEMENT!';
end($array);
if ($key === key($array))
echo 'LAST ELEMENT!';
}
end()
+ key()
en cada iteración del bucle; si son ambos, se llaman 4 métodos cada vez. De acuerdo, esas serían operaciones muy livianas y probablemente sean solo búsquedas de puntero, pero luego los documentos continúan especificando eso reset()
y end()
modificando el puntero interno de la matriz, entonces, ¿es más rápido que un contador? posiblemente no.
reset()
llamada antes del foreach y guardar el resultado en caché $first
.
Para encontrar el último elemento, encuentro que este código funciona cada vez:
foreach( $items as $item ) {
if( !next( $items ) ) {
echo 'Last Item';
}
}
[true,true,false,true]
. Pero personalmente usaré esto cada vez que esté tratando con una matriz que no contiene boolean false
.
next()
debe NUNCA ser utilizado dentro de un bucle foreach. Desordena el puntero interno de la matriz. Consulte la documentación para más información.
Una versión más simplificada de lo anterior y suponiendo que no esté utilizando índices personalizados ...
$len = count($array);
foreach ($array as $index => $item) {
if ($index == 0) {
// first
} else if ($index == $len - 1) {
// last
}
}
Versión 2 - Porque he detestado usar el else a menos que sea necesario.
$len = count($array);
foreach ($array as $index => $item) {
if ($index == 0) {
// first
// do something
continue;
}
if ($index == $len - 1) {
// last
// do something
continue;
}
}
if ($index == count($array) - 1)
. Ver aquí .
Puede eliminar el primer y el último elemento de la matriz y procesarlos por separado.
Me gusta esto:
<?php
$array = something();
$first = array_shift($array);
$last = array_pop($array);
// do something with $first
foreach ($array as $item) {
// do something with $item
}
// do something with $last
?>
Eliminar todo el formato a CSS en lugar de etiquetas en línea mejoraría su código y aceleraría el tiempo de carga.
También puede evitar mezclar HTML con lógica php siempre que sea posible.
Su página podría hacerse mucho más legible y mantenible separando cosas como esta:
<?php
function create_menu($params) {
//retrieve menu items
//get collection
$collection = get('xxcollection') ;
foreach($collection as $c) show_collection($c);
}
function show_subcat($val) {
?>
<div class="sub_node" style="display:none">
<img src="../images/dtree/join.gif" align="absmiddle" style="padding-left:2px;" />
<a id="'.$val['xsubcatid'].'" href="javascript:void(0)" onclick="getProduct(this , event)" class="sub_node_links" >
<?php echo $val['xsubcatname']; ?>
</a>
</div>
<?php
}
function show_cat($item) {
?>
<div class="node" >
<img src="../images/dtree/plus.gif" align="absmiddle" class="node_item" id="plus" />
<img src="../images/dtree/folder.gif" align="absmiddle" id="folder">
<?php echo $item['xcatname']; ?>
<?php
$subcat = get_where('xxsubcategory' , array('xcatid'=>$item['xcatid'])) ;
foreach($subcat as $val) show_subcat($val);
?>
</div>
<?php
}
function show_collection($c) {
?>
<div class="parent" style="direction:rtl">
<img src="../images/dtree/minus.gif" align="absmiddle" class="parent_item" id="minus" />
<img src="../images/dtree/base.gif" align="absmiddle" id="base">
<?php echo $c['xcollectionname']; ?>
<?php
//get categories
$cat = get_where('xxcategory' , array('xcollectionid'=>$c['xcollectionid']));
foreach($cat as $item) show_cat($item);
?>
</div>
<?php
}
?>
Un intento de encontrar el primero sería:
$first = true;
foreach ( $obj as $value )
{
if ( $first )
{
// do something
$first = false; //in order not to get into the if statement for the next loops
}
else
{
// do something else for all loops except the first
}
}
Simplemente esto funciona!
// Set the array pointer to the last key
end($array);
// Store the last key
$lastkey = key($array);
foreach($array as $key => $element) {
....do array stuff
if ($lastkey === key($array))
echo 'THE LAST ELEMENT! '.$array[$lastkey];
}
Gracias @billynoah por resolver el problema final .
if ($key === $lastkey)
.
if ($lastkey === $key)
?
PHP Warning: key() expects parameter 1 to be array, integer given in php shell code on line 1
key()
está obteniendo un número entero, no end()
. end()
" devuelve el valor del último elemento " y key()
espera una matriz como entrada.
1: ¿Por qué no usar una for
declaración simple ? Suponiendo que está utilizando una matriz real y no una Iterator
, puede verificar fácilmente si la variable del contador es 0 o uno menos que la cantidad total de elementos. En mi opinión, esta es la solución más limpia y comprensible ...
$array = array( ... );
$count = count( $array );
for ( $i = 0; $i < $count; $i++ )
{
$current = $array[ $i ];
if ( $i == 0 )
{
// process first element
}
if ( $i == $count - 1 )
{
// process last element
}
}
2: debe considerar el uso de conjuntos anidados para almacenar su estructura de árbol. Además, puede mejorar todo mediante el uso de funciones recursivas.
for
, puedes desplazarte de un lado 1
a otro n-1
y sacar el if
s del cuerpo. No tiene sentido revisarlos repetidamente.
La mejor respuesta:
$arr = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
foreach ($arr as $a) {
// This is the line that does the checking
if (!each($arr)) echo "End!\n";
echo $a."\n";
}
La respuesta más eficiente de @morg, a diferencia foreach
, solo funciona para matrices adecuadas, no para objetos de mapa hash. Esta respuesta evita la sobrecarga de una declaración condicional para cada iteración del bucle, como en la mayoría de estas respuestas (incluida la respuesta aceptada) al manejar específicamente el primer y último elemento, y recorrer los elementos intermedios.
La array_keys
función se puede utilizar para hacer que la respuesta eficiente funcione como foreach
:
$keys = array_keys($arr);
$numItems = count($keys);
$i=0;
$firstItem=$arr[$keys[0]];
# Special handling of the first item goes here
$i++;
while($i<$numItems-1){
$item=$arr[$keys[$i]];
# Handling of regular items
$i++;
}
$lastItem=$arr[$keys[$i]];
# Special handling of the last item goes here
$i++;
No he hecho una evaluación comparativa de esto, pero no se ha agregado ninguna lógica al ciclo, que es donde se produce el mayor éxito en el rendimiento, por lo que sospecho que los puntos de referencia proporcionados con la respuesta eficiente están bastante cerca.
Si quisieras funcionalizar este tipo de cosas, he dado un giro en esa función iterateList aquí . Sin embargo, es posible que desee comparar el código esencial si está muy preocupado por la eficiencia. No estoy seguro de cuánto sobrecarga introduce toda la invocación de función.
Para los scripts de generación de consultas SQL, o cualquier cosa que realice una acción diferente para el primer o el ú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 actual aceptada utiliza un bucle y una verificación dentro del bucle que se realizará en cada_site_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 punto de referencia casero mostró lo siguiente:
test1: 100000 ejecuciones del modelo morg
tiempo: 1869.3430423737 milisegundos
test2: 100000 ejecuciones de modelo si duran
tiempo: 3235.6359958649 milisegundos
Y, por lo tanto, está bastante claro que el cheque cuesta mucho y, por supuesto, empeora aún más a medida que agrega más cheques;)
$arr = array('one' => "1 1 1", 4 => 'Four', 1 => 'One'); $numItems = count($arr); $i=0; $firstitem=$arr[0]; echo $i . ': ' . $firstitem . ", "; $i++; while($i<$numItems-1){ $some_item=$arr[$i]; echo $i . ': ' . $some_item . ", "; $i++; } $last_item=$arr[$i]; echo $i . ': ' . $last_item . ", "; $i++;
saldrá:0: , 1: One, 2: ,
array()
hecho es {'one':"1 1 1",0:"",1:"One",2:"",3:"",4:"Four"}
pero los elementos vacíos se ignoran con el recuento, ¡estás contando el número de "cosas" definidas! ¡SACRIFICIO CON REGALO ENTRANTE! Esta respuesta merece recompensa, pero si @Morg. desaparecido, no tiene sentido. ¡Daría recompensas a una persona que probablemente no usará SO nuevamente! Si regresa y mejora su respuesta, ¡merece la recompensa!
array_keys
función, que puede tratar como una matriz. Vea mi respuesta "mejorada" .
$querySet = ""; foreach ($fieldSet as $key=>$value) { $value = $db->dbLink->quote($value); $querySet .= "$key = $value, "; } $querySet = substr_replace($querySet, "", -2); $queryString = "UPDATE users SET $querySet WHERE user_ID = '$user_ID'";
Con Keys and Values esto también funciona:
foreach ($array as $key => $value) {
if ($value === end($array)) {
echo "LAST ELEMENT!";
}
}
El uso de una variable booleana sigue siendo el más confiable, incluso si desea verificar la primera aparición de un $value
(lo encontré más útil en mi situación y en muchas situaciones) , como este:
$is_first = true;
foreach( $array as $value ) {
switch ( $value ) {
case 'match':
echo 'appeared';
if ( $is_first ) {
echo 'first appearance';
$is_first = false;
}
break;
}
}
if( !next( $array ) ) {
echo 'last value';
}
}
Entonces, ¿qué tal !next( $array )
encontrar el último $value
que devolverá true
si no hay ningún next()
valor para iterar?
Y prefiero usar un for
bucle en lugar de foreach
usar un contador, como este:
$len = count( $array );
for ( $i = 0; $i < $len; $i++ ) {
$value = $array[$i];
if ($i === 0) {
// first
} elseif ( $i === $len - 1 ) {
// last
}
// …
$i++;
}
Encontré este hilo cuando tengo el mismo problema. Solo necesito obtener el primer elemento, luego vuelvo a analizar mi código hasta que se me ocurre.
$firstElement = true;
foreach ($reportData->result() as $row)
{
if($firstElement) { echo "first element"; $firstElement=false; }
// Other lines of codes here
}
Los códigos anteriores son geniales y completos, pero si solo necesita el primer elemento, puede probar este código.
No estoy seguro si aún es necesario. Pero la siguiente solución debería funcionar con iteradores y no requiere count
.
<?php
foreach_first_last(array(), function ($key, $value, $step, $first, $last) {
echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
});
foreach_first_last(array('aa'), function ($key, $value, $step, $first, $last) {
echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
});
echo PHP_EOL;
foreach_first_last(array('aa', 'bb', 'cc'), function ($key, $value, $step, $first, $last) {
echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
});
echo PHP_EOL;
function foreach_first_last($array, $cb)
{
$next = false;
$current = false;
reset($array);
for ($step = 0; true; ++$step) {
$current = $next;
$next = each($array);
$last = ($next === false || $next === null);
if ($step > 0) {
$first = $step == 1;
list ($key, $value) = $current;
if (call_user_func($cb, $key, $value, $step, $first, $last) === false) {
break;
}
}
if ($last) {
break;
}
}
}
También puede usar una función anónima:
$indexOfLastElement = count($array) - 1;
array_walk($array, function($element, $index) use ($indexOfLastElement) {
// do something
if (0 === $index) {
// first element‘s treatment
}
if ($indexOfLastElement === $index) {
// last not least
}
});
Se deben mencionar tres cosas más:
array_values
primero debe canalizarla .$element
, debe pasarlo por referencia ( &$element
).$indexOfLastElement
interior de la use
construcción, nuevamente por referencia si es necesario.Puede usar el contador y la longitud de la matriz.
$ array = array (1,2,3,4); $ i = 0; $ len = cuenta ($ array); foreach ($ array como $ item) { if ($ i === 0) { // primero } else if ($ i === $ len - 1) { // último } // ... $ i ++; }
foreach ($arquivos as $key => $item) {
reset($arquivos);
// FIRST AHEAD
if ($key === key($arquivos) || $key !== end(array_keys($arquivos)))
$pdf->cat(null, null, $key);
// LAST
if ($key === end(array_keys($arquivos))) {
$pdf->cat(null, null, $key)
->execute();
}
}
Utilizando reset ($ array) y end ($ array)
<?php
$arrays = [1,2,3,4,5];
$first = reset($arrays);
$last = end($arrays);
foreach( $arrays as $array )
{
if ( $first == $array )
{
echo "<li>{$array} first</li>";
}
else if ( $last == $array )
{
echo "<li>{$array} last</li>";
}
else
{
echo "<li>{$array}</li>";
}
}
Prueba esto:
function children( &$parents, $parent, $selected ){
if ($parents[$parent]){
$list = '<ul>';
$counter = count($parents[$parent]);
$class = array('first');
foreach ($parents[$parent] as $child){
if ($child['id'] == $selected) $class[] = 'active';
if (!--$counter) $class[] = 'last';
$list .= '<li class="' . implode(' ', $class) . '"><div><a href="]?id=' . $child['id'] . '" alt="' . $child['name'] . '">' . $child['name'] . '</a></div></li>';
$class = array();
$list .= children($parents, $child['id'], $selected);
}
$list .= '</ul>';
return $list;
}
}
$output .= children( $parents, 0, $p_industry_id);
array_shift
yarray_pop
. Aunque esta es la solución que se me ocurrió si tuviera que implementar tal cosa, seguiría con la respuesta de Rok Kralj ahora.