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?


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.


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

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!


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

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.


Ś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
    }
}

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.


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

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!';
    }
}

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

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)

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


- zerwany link -
T30

3

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


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


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

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


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

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
}

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

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


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

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

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

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


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

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

0

Ostatni indeks możesz uzyskać bezpośrednio:

$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

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*/
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.