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++;
}
$i = 1
, vous n'avez pas à vous en soucier $len - 1
, utilisez simplement $len
.
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é d'itération actuelle à 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.
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()
à chaque itération de la boucle - si c'est les deux, c'est que 4 méthodes sont appelées à chaque fois. Certes, ce seraient des opérations très légères et ne sont probablement que des recherches de pointeur, mais les documents continuent de le spécifier reset()
et de end()
modifier le pointeur interne du tableau - est-ce donc plus rapide qu'un compteur? peut-être pas.
reset()
appel avant le foreach et à mettre le résultat en cache $first
.
Pour trouver le dernier élément, je trouve que ce morceau de code fonctionne à chaque fois:
foreach( $items as $item ) {
if( !next( $items ) ) {
echo 'Last Item';
}
}
[true,true,false,true]
. Mais personnellement, je l'utiliserai chaque fois que je traiterai avec un tableau qui ne contient pas de booléen false
.
next()
ne doit JAMAIS être utilisé dans une boucle foreach. Il gâche le pointeur de tableau interne. Consultez la documentation pour plus d'informations.
Une version plus simplifiée de ce qui précède et en supposant 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 j'en suis venu à détester utiliser le else 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;
}
}
if ($index == count($array) - 1)
. Voyez ici .
Vous pouvez supprimer les premier et dernier éléments du tableau et les traiter séparément.
Comme ça:
<?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
?>
La suppression de toute la mise en forme en CSS au lieu des balises en ligne améliorerait votre code et accélérerait le temps de chargement.
Vous pouvez également éviter de mélanger le HTML avec la logique php autant que possible.
Votre page pourrait être rendue beaucoup plus lisible et maintenable en séparant des choses comme ceci:
<?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
}
?>
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
}
}
Cela fonctionne simplement!
// 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];
}
Merci @billynoah pour avoir trié le problème 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()
obtient un entier, non end()
. end()
" renvoie la valeur du dernier élément " et key()
attend un tableau en entrée.
1: Pourquoi ne pas utiliser une simple for
déclaration? En supposant que vous utilisez un vrai tableau et non un tableau, Iterator
vous pouvez 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 la solution la plus propre et la plus compréhensible ...
$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 des ensembles imbriqués pour stocker votre structure arborescente. De plus, vous pouvez améliorer le tout en utilisant des fonctions récursives.
for
vous pouvez faire une boucle à partir 1
de n-1
et prendre la if
s hors du corps. Inutile de les vérifier à plusieurs reprises.
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";
}
La réponse la plus efficace de @morg, contrairement à foreach
, ne fonctionne que pour les tableaux appropriés, pas les objets de carte de hachage. Cette réponse évite la surcharge d'une instruction conditionnelle pour chaque itération de la boucle, comme dans la plupart de ces réponses (y compris la réponse acceptée) en traitant spécifiquement le premier et le dernier élément, et en bouclant sur les éléments du milieu.
La array_keys
fonction peut être utilisée pour faire fonctionner 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 à ce sujet, mais aucune logique n'a été ajoutée à la boucle, ce qui est le plus grand coup à la performance, alors 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 essayé une telle fonction iterateList ici . Cependant, vous voudrez peut-être comparer le code gist si vous êtes très préoccupé par l'efficacité. Je ne sais pas combien de frais généraux toute l'invocation de fonction introduit.
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 bonne (rapide) façon de procéder 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
Et il est donc tout à fait clair que le chèque coûte cher, et bien sûr, il devient encore pire avec les chèques plus variables que vous ajoutez;)
$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++;
affichera:0: , 1: One, 2: ,
array()
fait est {'one':"1 1 1",0:"",1:"One",2:"",3:"",4:"Four"}
mais les éléments vides sont ignorés avec count, vous comptez le nombre de "choses" définies !! SACRIFICE BOUNTY ENTRANT! Cette réponse mérite des primes, mais si @Morg. disparu, c'est inutile. Je donnerais une prime à une personne qui n'utilisera probablement plus SO! S'il revient et améliore sa réponse, il mérite la prime!
array_keys
fonction, que vous pouvez traiter comme un tableau. Voir ma réponse "améliorée" .
$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'";
Avec les clés et les valeurs, cela fonctionne également:
foreach ($array as $key => $value) {
if ($value === end($array)) {
echo "LAST ELEMENT!";
}
}
L'utilisation d'une variable booléenne est toujours la 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 que diriez-vous !next( $array )
de trouver le dernier $value
qui reviendra true
s'il n'y a pas de next()
valeur à itérer.
Et je préfère utiliser une for
boucle plutôt que 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++;
}
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 cela 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 excellents 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 également 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:
array_values
.$element
vous devez le passer par reference ( &$element
).$indexOfLastElement
intérieur de la use
construction, à nouveau par référence si nécessaire.Vous pouvez utiliser le compteur et la longueur du tableau.
$ tableau = tableau (1,2,3,4); $ i = 0; $ len = count ($ array); foreach ($ array as $ item) { si ($ i === 0) { // première } else if ($ i === $ len - 1) { // dernier } //… $ 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();
}
}
Utilisation de reset ($ array) et 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>";
}
}
Essaye ça:
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
etarray_pop
. Bien que ce soit la solution que j'aurais trouvée si je devais mettre en œuvre une telle chose, je m'en tiendrai à la réponse de Rok Kralj maintenant.