Risposte:
È possibile utilizzare un contatore:
$i = 0;
$len = count($array);
foreach ($array as $item) {
if ($i == 0) {
// first
} else if ($i == $len - 1) {
// last
}
// …
$i++;
}
$i = 1
, non devi preoccuparti $len - 1
, basta usare $len
.
Se si preferisce una soluzione che non richiede l'inizializzazione del contatore all'esterno del ciclo, propongo di confrontare la chiave di iterazione corrente con la funzione che indica l'ultimo / primo tasto dell'array.
Questo diventa in qualche modo più efficiente (e più leggibile) con il prossimo 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()
su ogni iterazione del ciclo - se è entrambi, allora sono 4 i metodi che vengono chiamati ogni volta. Certo, si tratterebbe di operazioni molto leggere e probabilmente sono solo ricerche di puntatori, ma i documenti continuano a specificarlo reset()
e a end()
modificare il puntatore interno dell'array - quindi è più veloce di un contatore? forse no.
reset()
chiamata prima della ricerca e memorizzare il risultato nella cache $first
.
Per trovare l'ultimo elemento, trovo che questo pezzo di codice funzioni ogni volta:
foreach( $items as $item ) {
if( !next( $items ) ) {
echo 'Last Item';
}
}
[true,true,false,true]
. Ma personalmente lo userò ogni volta che ho a che fare con un array che non contiene valori booleani false
.
next()
non dovrebbe MAI essere usato all'interno di un ciclo foreach. Colpisce il puntatore di array interno. Consulta la documentazione per ulteriori informazioni.
Una versione più semplificata di quanto sopra e presumendo che non si utilizzino indici personalizzati ...
$len = count($array);
foreach ($array as $index => $item) {
if ($index == 0) {
// first
} else if ($index == $len - 1) {
// last
}
}
Versione 2 - Perché sono venuto a detestare usando l'altro se non necessario.
$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)
. Vedi qui .
È possibile rimuovere il primo e l'ultimo elemento dall'array ed elaborarli separatamente.
Come questo:
<?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
?>
Rimuovere tutta la formattazione in CSS anziché i tag incorporati migliorerebbe il tuo codice e accelererebbe i tempi di caricamento.
Potresti anche evitare di mescolare HTML con logica php quando possibile.
La tua pagina potrebbe essere resa molto più leggibile e gestibile separando cose come questa:
<?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 tentativo di trovare il primo sarebbe:
$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
}
}
Semplicemente funziona!
// 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];
}
Grazie @billynoah per aver risolto il problema finale .
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()
sta ottenendo un numero intero, no end()
. end()
" restituisce il valore dell'ultimo elemento " e si key()
aspetta un array come input.
1: Perché non usare una semplice for
dichiarazione? Supponendo che tu stia utilizzando un array reale e non uno, Iterator
potresti facilmente verificare se la variabile del contatore è 0 o uno in meno dell'intero numero di elementi. Secondo me questa è la soluzione più pulita e comprensibile ...
$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: dovresti considerare l'utilizzo di set nidificati per memorizzare la struttura ad albero. Inoltre, puoi migliorare il tutto utilizzando le funzioni ricorsive.
for
possibile ciclo da 1
ad n-1
e prendere la if
s fuori dal corpo. Inutile controllarli ripetutamente.
Migliore risposta:
$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 risposta più efficiente di @morg, a differenza foreach
, funziona solo per array corretti, non per oggetti di mappa hash. Questa risposta evita il sovraccarico di un'istruzione condizionale per ogni iterazione del ciclo, come nella maggior parte di queste risposte (inclusa la risposta accettata) specificatamente gestendo in modo il primo e l'ultimo elemento e eseguendo il ciclo sugli elementi intermedi.
La array_keys
funzione può essere utilizzata per far funzionare la risposta efficiente come 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++;
Non ho fatto benchmarking su questo, ma non è stata aggiunta alcuna logica al loop, che è il più grande successo delle prestazioni, quindi sospetto che i benchmark forniti con la risposta efficiente siano abbastanza vicini.
Se volevi funzionalizzare questo genere di cose, ho preso una svolta a una tale funzione di elenco iterato qui . Tuttavia, potresti voler confrontare il codice gist se sei super preoccupato per l'efficienza. Non sono sicuro di quanto sovraccarico introduca tutta l'invocazione della funzione.
Per le query SQL che generano script o tutto ciò che compie un'azione diversa per il primo o l'ultimo elemento, è molto più veloce (quasi due volte più veloce) per evitare l'uso di controlli variabili non necessari.
La soluzione attualmente accettata utilizza un ciclo e un controllo all'interno del ciclo che verrà eseguito every_single_iteration, il modo corretto (veloce) per farlo è il seguente:
$numItems = count($arr);
$i=0;
$firstitem=$arr[0];
$i++;
while($i<$numItems-1){
$some_item=$arr[$i];
$i++;
}
$last_item=$arr[$i];
$i++;
Un piccolo benchmark fatto in casa ha mostrato quanto segue:
test1: 100000 serie di modelli morg
tempo: 1869.3430423737 millisecondi
test2: 100000 esecuzioni del modello se ultimo
tempo: 3235.6359958649 millisecondi
Ed è quindi abbastanza chiaro che il controllo costa molto, e ovviamente peggiora anche i controlli più variabili che aggiungi;)
$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++;
uscirà:0: , 1: One, 2: ,
array()
creato è {'one':"1 1 1",0:"",1:"One",2:"",3:"",4:"Four"}
ma gli elementi vuoti vengono ignorati con conteggio, si sta contando il numero di "cose" definite !! TAGLIENTE SACRIFICIO IN ARRIVO! Questa risposta merita generosità, ma se @Morg. andato, è inutile. Darei generosità a una persona che probabilmente non userà più SO! Se ritorna e migliora la sua risposta, merita la generosità!
array_keys
funzione, che puoi trattare come un array. Vedi la mia risposta "migliorata" .
$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 chiavi e valori funziona anche:
foreach ($array as $key => $value) {
if ($value === end($array)) {
echo "LAST ELEMENT!";
}
}
L'uso di una variabile booleana è ancora il più affidabile, anche se vuoi controllare la prima apparizione di un $value
(l'ho trovato più utile nella mia situazione e in molte situazioni) , come questo:
$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';
}
}
Allora che ne dici !next( $array )
di trovare l'ultimo $value
che tornerà true
se non c'ènext()
valore da iterare.
E preferisco usare un for
loop invece che foreach
se dovessi usare un contatore, in questo modo:
$len = count( $array );
for ( $i = 0; $i < $len; $i++ ) {
$value = $array[$i];
if ($i === 0) {
// first
} elseif ( $i === $len - 1 ) {
// last
}
// …
$i++;
}
Mi sono imbattuto in questa discussione quando ho lo stesso problema. Devo solo ottenere il primo elemento, quindi analizzo nuovamente il mio codice fino a quando non mi viene in mente.
$firstElement = true;
foreach ($reportData->result() as $row)
{
if($firstElement) { echo "first element"; $firstElement=false; }
// Other lines of codes here
}
I codici sopra sono fantastici e completi ma se hai bisogno solo del primo elemento, puoi provare questo codice.
Non sono sicuro se sia ancora necessario. Ma la seguente soluzione dovrebbe funzionare con gli iteratori e non richiede 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;
}
}
}
Puoi anche usare una funzione anonima:
$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
}
});
Altre tre cose da menzionare:
array_values
.$element
è necessario passarlo per riferimento (&$element
).$indexOfLastElement
all'interno del use
costrutto, di nuovo per riferimento se necessario.È possibile utilizzare il contatore e la lunghezza dell'array.
$ array = array (1,2,3,4); $ i = 0; $ len = count ($ array); foreach ($ array come $ item) { if ($ i === 0) { // primo } altrimenti if ($ i === $ len - 1) { // scorso } // ... $ 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();
}
}
Utilizzo di reset ($ array) e 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>";
}
}
Prova questo:
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
earray_pop
. Anche se questa è la soluzione che avrei trovato se avessi dovuto implementare una cosa del genere, continuerei ora con la risposta del Rok Kralj .