Znajdź ostatni element tablicy podczas korzystania z pętli foreach w PHP

215

Piszę kreatora zapytań SQL przy użyciu niektórych parametrów. W Javie bardzo łatwo jest wykryć ostatni element tablicy z wnętrza pętli for, po prostu sprawdzając bieżącą pozycję tablicy z długością tablicy.

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

W PHP mają indeksy niecałkowite umożliwiające dostęp do tablic. Musisz więc iterować tablicę za pomocą pętli foreach. Staje się to problematyczne, gdy musisz podjąć jakąś decyzję (w moim przypadku, aby dołączyć lub / i parametr podczas budowania zapytania).

Jestem pewien, że musi istnieć jakiś standardowy sposób na zrobienie tego.

Jak rozwiązujesz to w PHP?

Vaibhav Kamble
źródło
2
Czy próbujesz ustalić, czy powinieneś połączyć „AND” czy „OR” między częściami klauzuli where?
Darryl Hein
1
po prostu wskazując, że należy przechowywać sumę w zmiennej zamiast wywoływać metodę dla każdej iteracji. dla (int i = 0, int t = arr. długość; i <t; i ++).
OIS
Spójrz na to rozwiązanie: stackoverflow.com/a/29474468/1478566
vbarbarosh
użyj końca (tablica) użyj
Visakh B Sujathan

Odpowiedzi:

313

Wygląda na to, że chcesz czegoś takiego:

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

To powiedziawszy, nie musisz iterować po „tablicy” przy użyciu foreachPHP.

Richard Levasseur
źródło
Myślę, że wybiorę to rozwiązanie, ponieważ jest prawie podobne do kodu, który opublikowałem. Nawet odpowiedź Jeremy'ego jest odpowiednia, ale myślę, że w porównaniu z tą sprawą stała się mało skomplikowana. Nie przeprowadziłem żadnych testów, ale myślę, że ta odpowiedź będzie szybsza, ponieważ nie wyodrębnia tablicy kluczy. Będzie to miało prędkość O (1)
Vaibhav Kamble
18
$numItems = count($arr)trick nie jest potrzebny i zmniejsza czytelność - w PHP nie ma ograniczenia wydajności za dostęp do count ($ arr) za każdym razem. Powodem jest to, że liczba elementów jest zapisywana wewnętrznie jako specjalne pole w nagłówku tablicy i nie jest obliczana na bieżąco. Ta sztuczka pochodzi z innych języków (C, Java?, ...).
johndodo
7
To interesujące @johndodo, że nie ma ograniczenia wydajności za dostęp do count ($ arr) za każdym razem. Czy masz jakieś linki / źródła, w których dokumentowana jest ta optymalizacja? Dzięki!
zuallauz
2
To raczej smutne, że w PHP najbardziej poprawne rozwiązanie tego problemu wygląda raczej nieelegancko :(
kizzx2
1
@tomsihap $ i musi być zwiększany wewnątrz pętli, równolegle z iteracją tablicy. $ i musi reprezentować numer elementu w tablicy, aby można go było użyć do ustalenia, kiedy ostatni element został osiągnięty. Bez ++ pętla porównywałaby tylko „0” z całkowitą liczbą elementów.
Bobby Jack
201

Możesz uzyskać wartość ostatniego klucza tablicy za pomocą end(array_keys($array))i porównać ją z bieżącym kluczem:

$last_key = end(array_keys($array));
foreach ($array as $key => $value) {
    if ($key == $last_key) {
        // last element
    } else {
        // not last element
    }
}
Jeremy Ruten
źródło
2
+1 Zgadzam się - inne rozwiązania opierają się na tablicy o indeksach numerycznych.
Patrick Glandien
19
W mojej obronie moja odpowiedź nie polega na tym, że tablica ma klucze numeryczne :)
Richard Levasseur
2
porównywanie ciągów jest wolniejsze niż liczby całkowite i nie zawsze dokładne przy porównywaniu ciągów z liczbami całkowitymi (powinieneś przynajmniej użyć ===). Głosuję za tym.
OIS
4
jest elegancki, ale powoduje ŚCISŁĄ UWAGĘ, ponieważ „koniec” oczekuje wartości referencyjnej :(
Wiliam,
10
Naprawiono ZASTRZEŻENIE:$lastKey = array_search(end($array), $array);
Ajax
45

dlaczego tak skomplikowane?

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

Spowoduje to dodanie za każdą wartością oprócz ostatniej!

Trikks
źródło
2
Nie, jeśli następne wejście $ zawiera wartość logiczną false, co jest poważnym problemem w funkcji next ().
soulseekah
29
O ile się nie mylę, to nie działa, ponieważ wywołanie next () przesuwa wskaźnik tablicy, więc pomijasz każdy inny element w pętli.
Jordan Lev
2
Wydaje mi się, że to nie działa. Drugi ostatni element nie ma przecinka, ale powinien.
zuallauz
1
Jeśli wartość jest równa bool false, to nie działa. Nie drukuje również ostatniego przecinka między wartością od drugiej do ostatniej i ostatniej.
OIS
1
Uwaga dla każdego, kto chce tego użyć w PHP7 - wskaźnik tablicy nie porusza się w pętlach foreach, a to nie zadziała.
Scott Flack
26

Kiedy toEnd osiągnie 0, oznacza to, że jest na ostatniej iteracji pętli.

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

Ostatnia wartość jest nadal dostępna po pętli, więc jeśli chcesz użyć jej do innych rzeczy po pętli, lepiej:

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

Jeśli nie chcesz traktować ostatniej wartości jako specjalnych pętli wewnętrznych. Powinno to być szybsze, jeśli masz duże tablice. (Jeśli ponownie użyjesz tablicy po pętli w tym samym zakresie, musisz najpierw „skopiować” tablicę).

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

I aby odpowiedzieć na twoje pierwotne pytanie „w moim przypadku, aby dołączyć lub / i parametr podczas budowania zapytania”; spowoduje to zapętlenie wszystkich wartości, a następnie połączenie ich razem w ciąg znaków z „i” między nimi, ale nie przed pierwszą wartością lub po ostatniej wartości:

$params = [];
foreach ($array as $value) {
    $params[] = doSomething($value);
}
$parameters = implode(" and ", $params);
OIS
źródło
2
Oczywiście wykona - $ toEnd dla każdej iteracji, o to chodzi. Gdybym przesunął go poza pętlę, to już by nie działało.
OIS
Najprostsza zastosowana metoda. $lastValue = array_pop($array);Dziękuję Ci.
Elias Nicolas,
21

Istnieje już wiele odpowiedzi, ale warto również zajrzeć do iteratorów, zwłaszcza, że ​​poproszono o standardowy sposób:

$arr = range(1, 3);

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

Możesz znaleźć coś, co działa bardziej elastycznie, również w innych przypadkach.

hakre
źródło
Świetna odpowiedź. Rozumiem, że korzystasz z funkcji języka przeznaczonych do tego zadania. i=0;i ++i;zawsze wydawały się hackerskie w języku skryptowym takim jak PHP.
CheddarMonkey
15

Jednym ze sposobów może być wykrycie, czy iterator ma next. Jeśli do iteratora nie jest dołączone następne, oznacza to, że jesteś w ostatniej pętli.

foreach ($some_array as $element) {
    if(!next($some_array)) {
         // This is the last $element
    }
}
Raheel
źródło
Myślę, że jest to najłatwiejszy sposób i wymaga najmniejszej ilości kodu!
cześć im zvaehn
1
Nie działa z PHP 7+ jako „W PHP 7 foreach nie używa wewnętrznego wskaźnika tablicy”.
Damien Debin
8

Jeśli więc twoja tablica ma unikalne wartości, to określenie ostatniej iteracji jest banalne:

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

Jak widać, działa to, jeśli ostatni element pojawia się tylko raz w tablicy, w przeciwnym razie pojawi się fałszywy alarm. W tym przypadku nie trzeba porównywać kluczy (które na pewno są unikalne).

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

Zwróć też uwagę na operatora ścisłej kopii, co w tym przypadku jest dość ważne.

Rok Kralj
źródło
jest to dość nieefektywny sposób.
Twój zdrowy rozsądek
Nie. Nie jest. end () wykonuje O (1). Jest także krótszy niż inne rozwiązania i ładnie odczytuje -> Jeśli element jest równy końcowi tablicy, napisz „Last”.
Rok Kralj
Jest to ponad dwa razy wolniej niż mój pierwszy i ostatni przykład dla 100000 wartości.
OIS
5

Zakładając, że macie tablicę zapisaną w zmiennej ...

foreach($array as $key=>$value) 
{ 
    echo $value;
    if($key != count($array)-1) { echo ", "; }
}
Martin Heisterkamp
źródło
To jest bardzo proste i przydatne. Liczę tablicę najpierw tylko poza pętlą foreach, aby program nie musiał liczyć za każdym razem, gdy funkcja foreach ocenia każdy element.
Pathros,
3
To nie będzie działać na tablicach asocjacyjnych. Klucz $ nie zawsze jest liczbą.
Jonathan
5

aby uzyskać pierwszy i ostatni element z tablicy foreach

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

    if ($value === end($array)) {
        echo 'LAST ITEM!';
    }
}
Darkcoder
źródło
4

Nadal możesz używać tej metody z tablicami asocjacyjnymi:

$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;
}
pseudonim
źródło
1
Zmień $ key = $ array [$ i]; na $ key = $ klucze [$ i]; w pierwszej pętli for.
Narek,
4

Jeśli musisz zrobić coś dla każdego elementu oprócz pierwszego lub ostatniego i tylko jeśli w tablicy jest więcej niż jeden element, wolę następujące rozwiązanie.

Wiem, że istnieje wiele rozwiązań powyżej i opublikowanych miesiąc / rok przed moim, ale wydaje mi się, że jest to dość eleganckie samo w sobie. Sprawdzanie każdej pętli jest również czekiem logicznym w przeciwieństwie do czeku numerycznego „i = (count-1)”, który może pozwolić na mniejszy narzut.

Struktura pętli może wydawać się niewygodna, ale można ją porównać z kolejnością thead (początek), tfoot (koniec), tbody (bieżący) w znacznikach tabeli 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;
}

Na przykład, jeśli chodzi o tworzenie stron internetowych, jeśli chcesz dodać obramowanie do każdego elementu oprócz ostatniego na liście nieuporządkowanej (ul), możesz zamiast tego dodać obramowanie do każdego elementu oprócz pierwszego (CSS: first-child, obsługiwane przez IE7 + i Firefox / Webkit obsługuje tę logikę, podczas gdy: last-child nie jest obsługiwane przez IE7).

Możesz również ponownie użyć zmiennej $ first dla każdej zagnieżdżonej pętli, a wszystko będzie działać dobrze, ponieważ każda pętla powoduje, że $ first jest fałszywe podczas pierwszego procesu pierwszej iteracji (więc przerwy / wyjątki nie powodują problemów) .

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

Przykładowe dane wyjściowe:

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)
Ankit Aggarwal
źródło
Dzięki, to moje ulubione rozwiązanie! Jest bardzo elastyczny i kosztuje tylko wartość logiczną. BTW, myślę, że to zadziała dla tablicy zawierającej co najmniej jeden element (nie tylko więcej niż jeden element).
jc
4

To powinien być łatwy sposób na znalezienie ostatniego elementu:

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

Odniesienie: Link

Dulitha Kumarasiri
źródło
- zerwany link -
T30
3

Mam silne przeczucie, że u podstaw tego „problemu XY” OP chciał po prostu implode()działać.

Twój zdrowy rozsądek
źródło
1
prawdziwe. Są jednak przypadki, w których implode nie jest tak praktyczne. Wyobraź sobie na przykład, że próbujesz zaimplementować długi ciąg HTML z dużą ilością zmiennych dynamicznych. Jasne, możesz zrobić na nim ob_start / ob_get_clean lub po prostu zbudować go jako $ str = '...'. Ale są chwile, kiedy można to uznać za odrobinę
przesadę
3

Ponieważ Twoim celem znalezienia tablicy EOF jest tylko klej. Zapoznaj się z poniższą taktyką. Nie musisz wymagać 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
Angelin Nadar
źródło
2

Wygląda na to, że chcesz czegoś takiego:

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

foreach($array as $key => $value)
{
    if(end($array) === $value)
    {
       echo "last index!" . $value;
    }
}
Ashique CM
źródło
2
Używanie wartości zwykle nie jest dobrym pomysłem, ponieważ nie będzie działać poprawnie, jeśli tablica ma dwie identyczne wartości.
orrd
2

Nie dodawaj przecinka po ostatniej wartości:

Tablica:

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

Funkcja:

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

Wynik:

print $result;

Lorem ipsum dolor sit amet

Santo Boldižar
źródło
1

możesz wykonać count ().

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

lub jeśli szukasz TYLKO ostatniego elementu, możesz użyć end ().

end(arr);

zwraca tylko ostatni element.

i, jak się okazuje, MOŻESZ indeksować tablice php według liczb całkowitych. Jest całkowicie zadowolony

arr[1];
cześć
źródło
1
Wadą na końcu (arr) jest ustawienie wewnętrznego wskaźnika tablicy na ostatni element ..
Vijay
Nie, NIE powinieneś używać liczb całkowitych, aby uzyskać dostęp do tablic, chyba że wiesz, że klucze są numeryczne i sekwencyjne. Rozważmy: $a = array(0=>'A', 2=>'B', 'aaa'=>'C'). Co otrzymasz, jeśli uzyskasz dostęp $a[count($a)-1]?
johndodo
1

Możesz także zrobić coś takiego:

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

     // more code
}
KOGI
źródło
end zwraca wartość nie tablicę, więc sposób, w jaki ją stworzyłeś, nie działa. porównywanie ciągów jest również wolniejsze niż liczba całkowita.
OIS
Masz rację. powinien to być koniec (elementy $); $ endKey = klucz ($ elements);
KOGI
1

Podobają mi się następujące, ponieważ uważam, że jest dość schludny. Załóżmy, że tworzymy ciąg z separatorami między wszystkimi elementami: np. A, b, c

$first = true;
foreach ( $items as $item ) {
    $str = ($first)?$first=false:", ".$item;
}
Alastair Brayne
źródło
uprościć sprawę bez uprzedniego zadeklarowania $; użyć foreach ($ items jako $ key => $ item) następnie $ 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>";

}

Odniesienie

Ayman Elshehawy
źródło
0

Oto inny sposób, w jaki możesz to zrobić:

$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);
    }
}
Kevin
źródło
0

Jeśli cię rozumiem, wystarczy odwrócić tablicę i pobrać ostatni element za pomocą polecenia pop:

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);
James
źródło
0

Możesz także spróbować wykonać zapytanie ... pokazane tutaj za pomocą 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;
?>
znak
źródło
0

W przypadku skryptów generujących zapytania SQL lub czegokolwiek, co wykonuje inną akcję dla pierwszego lub ostatniego elementu, jest znacznie szybsze (prawie dwa razy szybsze), aby uniknąć niepotrzebnego sprawdzania zmiennych.

Obecnie akceptowane rozwiązanie wykorzystuje pętlę i sprawdzanie w pętli, które będzie wykonywane co każde pojedyncze sformułowanie, poprawny (szybki) sposób na wykonanie tego jest następujący:

$numItems = count($arr);
$i=0;
$firstitem=$arr[0];
$i++;
while($i<$numItems-1){
    $some_item=$arr[$i];
    $i++;
}
$last_item=$arr[$i];
$i++;

Mały domowy test porównawczy pokazał, co następuje:

test1: 100000 serii modelu Morg

czas: 1869.3430423737 milisekund

test2: 100000 serii modelu, jeśli ostatnia

czas: 3235.6359958649 milisekund

Morg.
źródło
0

Innym sposobem jest zapamiętanie wyniku poprzedniego cyklu pętli i wykorzystanie go jako wyniku końcowego:

    $result = $where = "";
    foreach ($conditions as $col => $val) {
        $result = $where .= $this->getAdapter()->quoteInto($col.' = ?', $val);
        $where .=  " AND ";
    }
    return $this->delete($result);
Leven
źródło
0

Osobiście korzystam z tego rodzaju konstrukcji, które umożliwiają łatwe korzystanie z elementów html <ul> i <li>: wystarczy zmienić równość dla innej właściwości ...

Tablica nie może zawierać fałszywych elementów, ale wszystkie inne elementy, które są rzutowane na fałszywe wartości logiczne.

$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;
}
MUY Belgium
źródło
0

Ostatni indeks możesz uzyskać bezpośrednio:

$numItems = count($arr);

echo $arr[$numItems-1];

Denis Omeri
źródło
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;?>
Zarpele
źródło
0

Oto moje rozwiązanie: Po prostu uzyskaj liczbę tablic minus 1 (ponieważ zaczynają się od 0).

$lastkey = count($array) - 1;
foreach($array as $k=>$a){
    if($k==$lastkey){
        /*do something*/
    }
}
ITWitch
źródło