Trouvez le dernier élément d'un tableau en utilisant une boucle foreach en PHP


215

J'écris un créateur de requête SQL en utilisant certains paramètres. En Java, il est très facile de détecter le dernier élément d'un tableau de l'intérieur de la boucle for en vérifiant simplement la position actuelle du tableau avec la longueur du tableau.

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

En PHP, ils ont des index non entiers pour accéder aux tableaux. Vous devez donc parcourir un tableau à l'aide d'une boucle foreach. Cela devient problématique lorsque vous devez prendre une décision (dans mon cas, ajouter ou / et paramètre lors de la construction de la requête).

Je suis sûr qu'il doit y avoir un moyen standard de procéder.

Comment résolvez-vous cela en PHP?


2
Essayez-vous de déterminer si vous devez concaténer un "ET" ou un "OU" entre les parties d'une clause where?
Darryl Hein

1
soulignant simplement que vous devez stocker le total dans une variable au lieu d'appeler une méthode pour chaque itération. pour (int i = 0, int t = arr.length; i <t; i ++).
OIS


Jetez un œil à cette solution: stackoverflow.com/a/29474468/1478566
vbarbarosh

Réponses:


313

Il semble que vous souhaitiez quelque chose comme ceci:

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

Cela étant dit, vous n'avez pas besoin d'itérer sur un "tableau" en utilisant foreachphp.


Je pense que je vais opter pour cette solution car elle est presque similaire au code que j'ai publié. Même la réponse de Jeremy est bien adaptée, mais je pense qu'elle est devenue peu complexe par rapport à celle-ci. Je n'ai effectué aucun test, mais je suppose que cette réponse sera plus rapide car elle n'extrait pas de tableau de clés. Cela doit avoir la vitesse O (1)
Vaibhav Kamble

18
$numItems = count($arr)l'astuce n'est pas nécessaire et réduit la lisibilité - en PHP, il n'y a pas de pénalité de performance pour accéder à count ($ arr) à chaque fois. La raison en est que le nombre d'éléments est enregistré en interne en tant que champ spécial dans l'en-tête du tableau et n'est pas calculé à la volée. Cette astuce provient d'autres langages (C, Java?, ...).
johndodo

7
C'est intéressant @johndodo qu'il n'y a pas de pénalité de performance pour accéder à chaque fois au compte ($ arr). Avez-vous des liens / sources vers lesquels cette optimisation particulière est documentée? Merci!
zuallauz

2
Il est plutôt triste qu'en PHP, la solution la plus correcte à ce problème semble plutôt inélégante :(
kizzx2

1
@tomsihap $ i doit être incrémenté à l'intérieur de la boucle, en tandem avec l'itération du tableau. $ i doit représenter le numéro de l'élément dans le tableau, afin qu'il puisse être utilisé pour déterminer quand le dernier élément a été atteint. Sans le ++, la boucle ne comparerait que "0" avec le nombre total d'éléments.
Bobby Jack

201

Vous pouvez obtenir la valeur de la dernière clé du tableau à l'aide end(array_keys($array))et la comparer à la clé actuelle:

$last_key = end(array_keys($array));
foreach ($array as $key => $value) {
    if ($key == $last_key) {
        // last element
    } else {
        // not last element
    }
}

2
+1 Je suis d'accord - les autres solutions reposent sur le tableau ayant des index numériques.
Patrick Glandien

19
Pour ma propre défense, ma réponse ne repose pas sur le tableau ayant des touches numériques :)
Richard Levasseur

2
la comparaison des chaînes est plus lente que les entiers, et pas toujours précise lors de la comparaison des chaînes aux entiers (vous devriez au moins avoir utilisé ===). Je vote cela.
OIS

4
il est élégant, mais provoque un AVIS STRICT car "end" attend une valeur de référence :(
Wiliam

10
Correction d'un AVIS STRICT:$lastKey = array_search(end($array), $array);
Ajax

45

pourquoi si compliqué?

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

Cela ajoutera un, derrière chaque valeur sauf la dernière!


2
Pas si la prochaine entrée $ contient une valeur booléenne false, ce qui est un problème majeur avec next ().
soulseekah

29
Sauf erreur, cela ne fonctionne pas car l'appel à next () fait avancer le pointeur du tableau, vous sautez donc tous les autres éléments de la boucle.
Jordan Lev

2
Ne semble pas fonctionner pour moi. L'avant-dernier élément ne reçoit pas la virgule, mais il le devrait.
zuallauz

1
Si la valeur équivaut à bool false, cela ne fonctionne pas. N'imprime pas non plus la dernière virgule entre l'avant-dernière et la dernière valeur.
OIS

1
Une note pour quiconque souhaite utiliser ceci en PHP7 - le pointeur de tableau ne se déplace pas dans les boucles foreach, et cela ne fonctionnera pas.
Scott Flack

26

Lorsque toEnd atteint 0, cela signifie qu'il est à la dernière itération de la boucle.

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

La dernière valeur est toujours disponible après la boucle, donc si vous voulez juste l'utiliser pour plus de choses après la boucle, c'est mieux:

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

Si vous ne souhaitez pas traiter la dernière valeur comme des boucles internes spéciales. Cela devrait être plus rapide si vous avez de grands tableaux. (Si vous réutilisez le tableau après la boucle à l'intérieur de la même portée, vous devez d'abord "copier" le tableau).

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

Et pour répondre à votre question d'origine "dans mon cas, ajouter ou / et paramètre lors de la construction de la requête"; cela bouclera sur toutes les valeurs, puis les joindra ensemble à une chaîne avec "et" entre elles mais pas avant la première valeur ou après la dernière valeur:

$params = [];
foreach ($array as $value) {
    $params[] = doSomething($value);
}
$parameters = implode(" and ", $params);

2
Bien sûr, il effectuera le - $ toEnd pour chaque itération, c'est le point. Si je le déplaçais hors de la boucle, cela ne fonctionnerait plus.
OIS

La méthode la plus simple jamais utilisée. $lastValue = array_pop($array);Je vous remercie.
Elias Nicolas

21

Il existe déjà de nombreuses réponses, mais cela vaut également la peine d'examiner les itérateurs, d'autant plus qu'il a été demandé de manière standard:

$arr = range(1, 3);

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

Vous pourriez également trouver quelque chose qui fonctionne plus flexible pour d'autres cas.


Très bonne réponse. J'apprécie que vous utilisiez les fonctionnalités du langage qui sont destinées à la tâche. i=0;et ++i;ont toujours semblé hackish dans un langage de script comme PHP.
CheddarMonkey

15

Une façon pourrait être de détecter si l'itérateur l'a fait next. S'il n'y a pas de prochain attaché à l'itérateur, cela signifie que vous êtes dans la dernière boucle.

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

Je pense que c'est le moyen le plus simple et nécessite le moins de code!
salut im zvaehn

1
Ne fonctionne pas avec PHP 7+ car "En PHP 7, foreach n'utilise pas le pointeur de tableau interne.".
Damien Debin

8

Donc, si votre tableau a des valeurs de tableau uniques, déterminer la dernière itération est trivial:

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

Comme vous le voyez, cela fonctionne si le dernier élément n'apparaît qu'une seule fois dans le tableau, sinon vous obtenez une fausse alarme. Dans ce cas, vous devez comparer les clés (qui sont uniques à coup sûr).

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

Notez également l'opérateur de coparision strict, ce qui est assez important dans ce cas.


c'est assez inefficace.
Votre bon sens

Nan. Ce n'est pas. end () exécute O (1). Il est également plus court que les autres solutions, et il se lit bien -> Si l'élément est égal à la fin du tableau, écrivez "Last".
Rok Kralj

C'est plus de deux fois plus lent que mes premiers et derniers exemples pour 100 000 valeurs.
OIS

5

En supposant que le tableau soit stocké dans une variable ...

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

C'est très simple et utile. Je ne compterais que le tableau en premier en dehors de la boucle foreach pour que le programme n'ait pas à compter chaque fois que la fonction foreach évalue chaque élément.
Pathros

3
Cela ne fonctionnera pas sur les tableaux associatifs. La touche $ n'est pas toujours un nombre.
Jonathan

5

pour obtenir le premier et le dernier élément du tableau foreach

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

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

4

Vous pouvez toujours utiliser cette méthode avec des tableaux associatifs:

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

1
Veuillez changer $ key = $ array [$ i]; à $ key = $ keys [$ i]; dans la première boucle for.
Narek

4

Si vous devez faire quelque chose pour chaque élément sauf le premier ou le dernier et seulement s'il y a plus d'un élément dans le tableau, je préfère la solution suivante.

Je sais qu'il existe de nombreuses solutions ci-dessus et publiées des mois / un an avant le mien, mais c'est quelque chose que je trouve assez élégant en soi. La vérification de chaque boucle est également une vérification booléenne par opposition à une vérification numérique "i = (count-1)", qui peut permettre de réduire les frais généraux.

La structure de la boucle peut sembler gênante, mais vous pouvez la comparer à l'ordre de la tête (début), tfoot (fin), tbody (actuel) dans les balises de table 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;
}

Par exemple, en termes de développement Web, si vous souhaitez ajouter une bordure inférieure à chaque élément à l'exception du dernier d'une liste non ordonnée (ul), vous pouvez plutôt ajouter une bordure supérieure à chaque élément sauf le premier (le CSS: premier enfant, pris en charge par IE7 + et Firefox / Webkit prend en charge cette logique, alors que: dernier enfant n'est pas pris en charge par IE7).

Vous pouvez vous sentir libre de réutiliser la variable $ first pour chaque boucle imbriquée également et les choses fonctionneront très bien puisque chaque boucle rend $ first faux pendant le premier processus de la première itération (donc les ruptures / exceptions ne causeront pas de problèmes) .

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

Exemple de sortie:

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)

Merci, c'est ma solution préférée! Il est très flexible et ne coûte qu'un booléen. BTW, je pense que cela fonctionnera pour le tableau contenant au moins un élément aussi (pas seulement plus d' un élément).
jc

4

Cela devrait être le moyen facile de trouver le dernier élément:

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

Référence: Lien


- lien cassé -
T30

3

J'ai le fort sentiment qu'à l'origine de ce "problème XY", l'OP voulait juste implode()fonctionner.


1
vrai. Il y a des cas où l'implosion n'est tout simplement pas aussi pratique. Imaginez par exemple essayer d'imploser une longue chaîne de code HTML avec beaucoup de variables dynamiques. Bien sûr, vous pouvez faire un ob_start / ob_get_clean dessus, ou simplement le construire comme $ str = '...'. Mais, il y a des moments où cela pourrait être considéré comme un peu exagéré
Alastair Brayne

3

Comme votre intention de trouver le réseau EOF est juste pour la colle. Découvrez la tactique ci-dessous. Vous n'avez pas besoin de l'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


2

Il semble que vous souhaitiez quelque chose comme ceci:

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

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

2
L'utilisation de la valeur n'est généralement pas une bonne idée car elle ne fonctionnera pas correctement si le tableau a deux valeurs identiques.
orrd

2

N'ajoutez pas de virgule après la dernière valeur:

Le tableau:

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

La fonction:

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

Le résultat:

print $result;

Lorem ipsum dolor sit amet


1

vous pouvez faire un compte ().

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

ou si vous recherchez UNIQUEMENT le dernier élément, vous pouvez utiliser end ().

end(arr);

renvoie uniquement le dernier élément.

et, en fin de compte, vous POUVEZ indexer les tableaux php par des entiers. Il est parfaitement satisfait de

arr[1];

1
L'inconvénient de end (arr) est qu'il place le pointeur interne du tableau sur le dernier élément.
Vijay

Non, vous NE DEVEZ PAS utiliser d'entiers pour accéder aux tableaux à moins que vous ne sachiez que les clés sont numériques et séquentielles. Considérez: $a = array(0=>'A', 2=>'B', 'aaa'=>'C'). Qu'obtenez-vous si vous y accédez $a[count($a)-1]?
johndodo

1

Vous pouvez également faire quelque chose comme ceci:

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

     // more code
}

end renvoie la valeur et non le tableau, donc la façon dont vous l'avez fait ne fonctionne pas. la comparaison des chaînes est également plus lente que l'entier.
OIS

Vous avez raison. ce doit être end ($ elements); $ endKey = key ($ elements);
KOGI

1

J'aime un peu ce qui suit car je pense que c'est assez soigné. Supposons que nous créons une chaîne avec des séparateurs entre tous les éléments: par exemple a, b, c

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

rendre les choses plus simples sans déclarer $ first; utiliser foreach ($ items as $ key => $ item) puis $ str = ($ key == 0)?
Milan Rilex Ristic

1
foreach ($array as $key => $value) {

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

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

}

Référence


0

Voici une autre façon de procéder:

$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

Si je vous comprends, alors tout ce dont vous avez besoin est d'inverser le tableau et d'obtenir le dernier élément par une commande pop:

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);

0

Vous pouvez également essayer ceci pour faire votre requête ... affichée ici avec 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

Pour les scripts générant des 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) d'éviter d'utiliser des vérifications de variables inutiles.

La solution actuellement acceptée utilise une boucle et une vérification dans la boucle qui sera effectuée à chaque_single_iteration, la manière correcte (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 petit repère fait maison a montré ce qui suit:

test1: 100000 exécutions de modèle morg

temps: 1869.3430423737 millisecondes

test2: 100000 exécutions du modèle si dernier

temps: 3235.6359958649 millisecondes


0

Une autre façon de procéder consiste à se souvenir du résultat du cycle de boucle précédent et à l'utiliser comme résultat final:

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

0

J'utilise personnellement ce type de construction qui permet une utilisation facile avec les éléments html <ul> et <li>: changez simplement l'égalité pour une autre propriété ...

Le tableau ne peut pas contenir de faux éléments mais tous les autres éléments qui sont convertis en faux booléen.

$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

Vous pouvez directement obtenir le dernier index en:

$numItems = count($arr);

echo $arr[$numItems-1];


0
<?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

Voici ma solution: obtenez simplement le nombre de votre tableau, moins 1 (car ils commencent en 0).

$lastkey = count($array) - 1;
foreach($array as $k=>$a){
    if($k==$lastkey){
        /*do something*/
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.