Comment déterminer la première et la dernière itération dans une boucle de foreach?

la question est simple. J'ai une boucle foreach dans mon code:

foreach($array as $element) {
    //code
}

dans cette boucle, je veux réagir différemment quand nous sommes en première ou dernière itération.

Comment faire?

413
demandé sur Rok Kralj 2009-07-01 20:57:59

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++;
}
349
répondu Gumbo 2017-01-10 02:25:07

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!';
}
850
répondu Rok Kralj 2018-08-18 20:46:27

pour trouver le dernier article, je trouve ce morceau de code fonctionne à chaque fois:

foreach( $items as $item ) {
    if( !next( $items ) ) {
        echo 'Last Item';
    }
}
79
répondu Yojance 2015-03-23 20:53:10

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;
    }
}
68
répondu Hayden 2017-12-03 00:24:54

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
}
?>
31
répondu Carlos Lima 2009-07-01 17:46:17

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
  }
}
14
répondu sstauross 2014-10-29 11:30:46

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!';
}
14
répondu Sydwell 2015-10-25 20:18:29

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.

10
répondu okoman 2011-10-30 23:18:22

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

}
8
répondu Ivan 2013-06-11 05:29:53

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

5
répondu Morg. 2011-08-09 13:33:32

, 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.

5
répondu TheMadDeveloper 2017-05-23 12:02:46

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++;
}
4
répondu 5ervant 2015-09-27 17:26:34

avec touches et valeurs cela fonctionne aussi bien:

foreach ($array as $key => $value) {
    if ($value === end($array)) {
        echo "LAST ELEMENT!";
    }
}
3
répondu Benibr 2015-03-04 00:51:11

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.

3
répondu paul 2017-03-11 11:34:21

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;
        }
    }
}
1
répondu vbarbarosh 2015-04-06 15:39:32

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 construction use , encore une fois par référence si nécessaire.
0
répondu undko 2017-12-26 00:41:05

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++;
    }
0
répondu Jesus Erwin Suarez 2018-05-02 00:41:32

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);
-1
répondu PureField 2012-10-26 04:44:29