Comment déterminer la première et la dernière itération dans une boucle de foreach?
18 réponses
vous pouvez utiliser un compteur:
$i = 0;
$len = count($array);
foreach ($array as $item) {
if ($i == 0) {
// first
} else if ($i == $len - 1) {
// last
}
// …
$i++;
}
si vous préférez une solution qui ne nécessite pas l'initialisation du compteur en dehors de la boucle, je vous propose de comparer la clé itération courante avec la fonction qui vous indique la dernière / première clé du tableau.
cela devient un peu plus efficace (et plus lisible) avec le prochain PHP 7.3.
Solution pour PHP 7.3 et plus:
foreach($array as $key => $element) {
if ($key === array_key_first($array))
echo 'FIRST ELEMENT!';
if ($key === array_key_last($array))
echo 'LAST ELEMENT!';
}
Solution pour toutes les versions PHP:
foreach($array as $key => $element) {
reset($array);
if ($key === key($array))
echo 'FIRST ELEMENT!';
end($array);
if ($key === key($array))
echo 'LAST ELEMENT!';
}
pour trouver le dernier article, je trouve ce morceau de code fonctionne à chaque fois:
foreach( $items as $item ) {
if( !next( $items ) ) {
echo 'Last Item';
}
}
une version simplifiée de ce qui précède et présumant que vous n'utilisez pas d'index personnalisés...
$len = count($array);
foreach ($array as $index => $item) {
if ($index == 0) {
// first
} else if ($index == $len - 1) {
// last
}
}
Version 2-parce que je suis venu à détester l'utilisation de l'autre sauf si nécessaire.
$len = count($array);
foreach ($array as $index => $item) {
if ($index == 0) {
// first
// do something
continue;
}
if ($index == $len - 1) {
// last
// do something
continue;
}
}
vous pouvez supprimer les premier et dernier éléments du tableau et les traiter séparément.
Comme ceci:
<?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
?>
supprimer tout le formatage à css au lieu d'étiquettes en ligne améliorerait votre code et accélérerait le temps de chargement.
vous pouvez également éviter de mélanger HTML avec la logique php dans la mesure du possible.
Votre page pourrait être rendue beaucoup plus lisible et maintenable en séparant des choses comme ceci:
<?php
function create_menu($params) {
//retirive 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
}
?>
une tentative pour trouver le premier serait:
$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
}
}
tout simplement cela fonctionne!
//Store the last key
$lastkey = key(end($array));
foreach($array as $key => $element) {
....do array stuff
if ($lastkey === key($array))
echo 'LAST ELEMENT!';
}
1: Pourquoi ne pas utiliser une simple déclaration for
? En supposant que vous utilisez un vrai tableau et non un Iterator
vous pourriez facilement vérifier si la variable de compteur est 0 ou un de moins que le nombre entier d'éléments. À mon avis c'est le plus propre et compréhensible solution...
$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: vous devriez envisager d'utiliser ensembles imbriqués pour stocker votre structure d'arbre. En outre, vous pouvez améliorer l'ensemble de la chose en utilisant récursive fonction.
meilleure réponse:
$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";
}
pour les scripts de génération de requêtes SQL, ou tout ce qui fait une action différente pour le premier ou le dernier élément, il est beaucoup plus rapide (presque deux fois plus rapide) pour éviter d'utiliser des vérifications de variables inutiles.
la solution actuellement acceptée utilise une boucle et un contrôle à l'intérieur de la boucle qui sera faite every_single_iteration, la bonne façon (rapide) de le faire est la suivante:
$numItems = count($arr);
$i=0;
$firstitem=$arr[0];
$i++;
while($i<$numItems-1){
$some_item=$arr[$i];
$i++;
}
$last_item=$arr[$i];
$i++;
Un peu maison de référence ont révélé ce qui suit:
test1: 100000 pistes de modèle morg
time: 1869.3430423737 millisecondes
test2: 100000 essais du modèle si le dernier
time: 3235.6359958649 millisecondes
et il est donc tout à fait clair que le chèque coûte beaucoup, et bien sûr il est encore pire les chèques plus variables que vous ajoutez;)
, La plus réponse efficace de @morg, à la différence de foreach
, ne fonctionne que pour le bon de tableaux, pas de hachage les objets de la carte. Cette réponse permet d'éviter la présentation d'un énoncé conditionnel pour chaque itération de la boucle, comme dans la plupart de ces réponses (y compris la réponse acceptée) par spécifiquement traiter le premier et le dernier élément, et en boucle sur les éléments du milieu.
Le array_keys
fonction peut être utilisée pour rendre la réponse efficace comme 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++;
Je n'ai pas fait de benchmarking sur ce point, mais aucune logique n'a été ajoutée à la boucle, qui est celle où la performance est la plus touchée, donc je soupçonne que les benchmarks fournis avec la réponse efficace sont assez proches.
si vous vouliez fonctionnaliser ce genre de chose, j'ai pris un swing à un tel iterateList fonction ici . Bien que, vous pourriez vouloir comparer le code gist si vous êtes super préoccupé par l'efficacité. Je ne suis pas sûr de savoir combien de temps la fonction invocation introduit.
utiliser une variable booléenne est toujours le plus fiable, même si vous voulez vérifier la première apparition d'un $value
(Je l'ai trouvé plus utile dans ma situation et dans de nombreuses situations) , comme ceci:
$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';
}
}
alors pourquoi pas !next( $array )
pour trouver le dernier $value
qui retournera true
s'il n'y a pas de valeur next()
à itérer.
et je préfère utiliser une boucle for
au lieu de foreach
si j'allais utiliser un compteur, comme ceci:
$len = count( $array );
for ( $i = 0; $i < $len; $i++ ) {
$value = $array[$i];
if ($i === 0) {
// first
} elseif ( $i === $len - 1 ) {
// last
}
// …
$i++;
}
avec touches et valeurs cela fonctionne aussi bien:
foreach ($array as $key => $value) {
if ($value === end($array)) {
echo "LAST ELEMENT!";
}
}
je suis tombé sur ce fil, quand j'ai le même problème. Je n'ai besoin que du premier élément, puis je ré-analyse mon code jusqu'à ce que ça me vienne à l'esprit.
$firstElement = true;
foreach ($reportData->result() as $row)
{
if($firstElement) { echo "first element"; $firstElement=false; }
// Other lines of codes here
}
les codes ci-dessus sont grands et complets, mais si vous n'avez besoin que du premier élément, vous pouvez essayer ce code.
je ne sais Pas si c'est encore nécessaire. Mais la solution suivante devrait fonctionner avec des itérateurs et ne nécessite pas 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;
}
}
}
vous pouvez aussi utiliser une fonction anonyme:
$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
}
});
trois autres choses doivent être mentionnées:
- si votre tableau n'est pas strictement indexé (numériquement) vous devez pipe votre tableau par
array_values
d'abord. - si vous devez modifier le
$element
vous devez le passer par référence (&$element
). - toutes les variables extérieures à la fonction anonyme dont vous avez besoin à l'intérieur, vous devrez les énumérer à côté de
$indexOfLastElement
dans la constructionuse
, encore une fois par référence si nécessaire.
vous pouvez utiliser la longueur du compteur et du tableau.
$array = array(1,2,3,4); $i = 0; $len = count($array); foreach ($array as $item) { if ($i === 0) { // first } else if ($i === $len - 1) { // last } // … $i++; }
essayez ceci:
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);