PHP'de foreach döngüsü kullanırken bir dizinin son öğesini bulma


215

Bazı parametreleri kullanarak bir SQL sorgu yaratıcısı yazıyorum. Java'da, geçerli dizi konumunu sadece dizi uzunluğu ile kontrol ederek for döngüsünün içinden bir dizinin son öğesini algılamak çok kolaydır.

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

PHP'de dizilere erişmek için tamsayı olmayan dizinler vardır. Bu nedenle, foreach döngüsü kullanarak bir dizi üzerinden yineleme yapmanız gerekir. Bazı kararlar almanız gerektiğinde bu sorunlu hale gelir (benim durumumda sorgu oluştururken veya / ve parametre eklemek için).

Eminim bunu yapmanın standart bir yolu olmalı.

PHP'de bunu nasıl çözersiniz?


2
Where yan tümcesinin bölümleri arasına "VE" veya "VEYA" eklemeniz gerekip gerekmediğini mi belirlemeye çalışıyorsunuz?
Darryl Hein

1
her yineleme için bir yöntem çağırmak yerine toplamı bir değişkende depolamanız gerektiğini belirtmek. için (int i = 0, int t = arr.length; i <t; i ++).
OIS


Bu çözüme bir göz atın: stackoverflow.com/a/29474468/1478566
vbarbarosh

use end (arrray) use
simmilar

Yanıtlar:


313

Kulağa şöyle bir şey istiyormuşsunuz gibi geliyor:

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

Olduğu söyleniyor, foreachphp kullanarak bir "dizi" üzerinde yineleme -have- yok .


Ben hemen hemen yayınlanan koduna benzer olduğu için bu çözüm için gidecek düşünüyorum. Jeremy'nin cevabı bile çok uygun ama bence buna göre biraz karmaşık. Ben herhangi bir test yaptılar değil ama keys.This dizisi O (1) hızına sahip olacaktır ayıklanması değil bu cevap daha hızlı olacaktır sanırım
Vaibhav Kamble

18
$numItems = count($arr)hile gerekli değildir ve okunabilirliği azaltır - PHP'de her seferinde sayıya ($ arr) erişmek için performans cezası yoktur. Nedeni ürün içten dizi başlığında özel alan olarak kaydedilir saymak ve olmasıdır değil on-the-fly hesapladık. Bu hile diğer dillerden geliyor (C, Java?, ...).
johndodo

7
İlginçtir @johndodo, her seferinde sayıya ($ arr) erişmek için performans cezası olmaması. Bu optimizasyonun belgelendiği bağlantılarınız / kaynaklarınız var mı? Teşekkürler!
zuallauz

2
PHP'de bu soruna en doğru çözümün oldukça
yetersiz

1
@tomsihap $ i, dizi yinelemesine paralel olarak, döngü içinde artırılmalıdır. $ i, son öğeye ne zaman ulaşıldığını belirlemek için kullanılabilmesi için dizideki öğenin sayısını temsil etmelidir. ++ olmadan, döngü "0" değerini toplam öğe sayısı ile karşılaştırır.
Bobby Jack

201

Kullanarak dizinin son anahtarının değerini alabilir end(array_keys($array))ve geçerli anahtarla karşılaştırabilirsiniz:

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

2
+1 Kabul ediyorum - diğer çözümler sayısal dizinlere sahip diziye dayanır.
Patrick Glandien

19
Kendi savunmamda, cevabım sayısal tuşlara sahip diziye dayanmıyor :)
Richard Levasseur

2
dize karşılaştırması tamsayılardan daha yavaştır ve dizeleri tamsayılarla karşılaştırırken her zaman doğru değildir (en azından === kullanmalısınız). Buna oy veriyorum.
OIS

4
zariftir, ancak "son" bir referans değer beklediğinden STRICT BİLDİRİMİ'ne neden olur :(
Wiliam

10
STRICT BİLDİRİMİ için düzeltme:$lastKey = array_search(end($array), $array);
Ajax

45

neden bu kadar karmaşık?

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

Bu, sonuncusu hariç her değerin arkasına a ekleyecektir!


2
Bir sonraki $ girdisi, bir boolean false değeri içeriyorsa, next () ile büyük bir problemdir.
soulseekah

29
Yanılmıyorsam, next () çağrısı dizi işaretçisini ilerlettiğinden çalışmaz, bu yüzden döngüdeki diğer tüm öğeleri atlarsınız.
Jordan Lev

2
Benim için çalışmıyor gibi görünüyor. İkinci son öğe virgül almaz ancak almalıdır.
zuallauz

1
Değer bool false değerine eşitse, çalışmaz. Ayrıca ikinci ila son ve son değer arasındaki son virgül yazdırılmaz.
OIS

1
PHP7'de kullanmak isteyen herkes için bir not - dizi işaretçisi foreach döngülerinde hareket etmez ve bu çalışmaz.
Scott Flack

26

ToEnd, 0'a ulaştığında, döngünün son tekrarında olduğu anlamına gelir.

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

Döngüden sonra son değer hala kullanılabilir, bu yüzden döngüden sonra daha fazla şey için kullanmak istiyorsanız, bu daha iyidir:

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

Son değeri döngüler içinde özel olarak değerlendirmek istemiyorsanız. Büyük dizileriniz varsa bu daha hızlı olmalıdır. (Diziyi aynı kapsamdaki döngüden sonra yeniden kullanırsanız, önce diziyi "kopyalamanız gerekir").

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

Ve orijinal sorunuzu cevaplamak için "benim durumumda sorgu oluşturmak için ve / veya parametre oluşturmak"; bu, tüm değerlerin üzerinden geçer ve ardından aralarında "ve" bulunan bir dizeye birleştirilir, ancak ilk değerden önce veya son değerden sonra olmaz:

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

2
Tabii ki her yineleme için - $ toEnd gerçekleştirecek, işte bu. Eğer döngünün dışına çıkarırsam, artık işe yaramaz.
OIS

Şimdiye kadar kullanılan en basit yöntem. $lastValue = array_pop($array);Teşekkür ederim.
Elias Nicolas

21

Zaten birçok cevap var, ancak özellikle standart bir yol istendiği için yineleyicilere de bakmaya değer:

$arr = range(1, 3);

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

Diğer durumlar için de daha esnek çalışan bir şey bulabilirsiniz.


Mükemmel cevap. Görev için tasarlanan dilin özelliklerini kullandığınız için teşekkür ederiz. i=0;ve ++i;her zaman PHP gibi bir betik dilinde hackish görünüyordu.
CheddarMonkey

15

Bir yol, yineleyicinin olup olmadığını tespit etmek olabilir next. Yineleyiciye bir sonraki bağlı değilse, son döngüde olduğunuz anlamına gelir.

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

Bunun en kolay yol olduğunu ve en az miktarda kod gerektirdiğini düşünüyorum!
hi im zvaehn

1
PHP 7+ ile çalışmaz "PHP 7'de, foreach dahili dizi işaretçisini kullanmaz.".
Damien Debin

8

Dolayısıyla, dizinizde benzersiz dizi değerleri varsa, son yinelemeyi belirlemek önemsizdir:

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

Gördüğünüz gibi, bu son öğe dizide sadece bir kez görünüyorsa çalışır, aksi takdirde yanlış alarm alırsınız. İçinde değil, anahtarları karşılaştırmanız gerekir (ki bu kesinlikle benzersizdir).

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

Ayrıca, bu durumda oldukça önemli olan sıkı coparision operatörüne de dikkat edin.


bu oldukça verimsiz bir yol.
Ortak Duygunuz

Hayır! O değil. end (), O (1) 'i gerçekleştirir. Ayrıca diğer çözümlerden daha kısadır ve iyi okunur -> Öğe dizinin sonuna eşitse "Son" yaz.
Rok Kralj

Bu, 100000 değerleri için ilk ve son örneklerimin iki katından daha yavaş.
OIS

5

Diziyi bir değişkende sakladığınız varsayılarak ...

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

Bu çok basit ve kullanışlıdır. Ben sadece foreach döngü dışında ilk dizi saymak böylece foreach işlevi her öğeyi değerlendirmek her zaman saymak zorunda kalmazsınız.
Pathros

3
Bu ilişkisel diziler üzerinde çalışmaz. $ tuşu her zaman bir sayı değildir.
Jonathan

5

foreach dizisinden ilk ve son öğeyi almak için

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

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

4

Yine de ilişkilendirilebilir dizilerle bu yöntemi kullanabilirsiniz:

$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
Lütfen $ key = $ array [$ i] 'ı değiştirin; - $ anahtar = $ anahtarlar [$ i]; ilk döngü için.
Narek

4

İlk veya son hariç her öğe için bir şeyler yapmanız gerekiyorsa ve yalnızca dizide birden fazla öğe varsa, aşağıdaki çözümü tercih ederim.

Yukarıda birçok çözüm olduğunu biliyorum ve aylar / bir yıl önce yayınladım, ama bu kendi başına oldukça zarif olduğunu düşündüğüm bir şey. Her döngüyü kontrol et, sayısal "i = (sayım-1)" kontrolünün aksine bir boole kontrolüdür, bu da daha az ek yüke izin verebilir.

Döngünün yapısı garip gelebilir, ancak HTML tablosu etiketlerinde thead (başlangıç), tfoot (son), tbody (geçerli) sıralamasıyla karşılaştırabilirsiniz.

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

Örneğin, web geliştirme terimleriyle, sırasız bir listede (ul) sonuncusu hariç her öğeye kenarlık eklemek istiyorsanız, bunun yerine ilk öğenin (CSS: IE7 + ve Firefox / Webkit tarafından desteklenen ilk çocuk bu mantığı desteklerken, son çocuk IE7 tarafından desteklenmez).

Her bir iç içe döngü için $ first değişkenini yeniden kullanmakta özgürsünüz ve her döngü ilk yinelemenin ilk işlemi sırasında $ first false yapar (bu nedenle molalar / istisnalar sorunlara neden olmaz) .

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

Örnek çıktı:

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)

Teşekkürler, bu benim en sevdiğim çözüm! Çok esnektir ve sadece bir boole maliyeti vardır. BTW, bu en az bir öğe de (sadece birden fazla öğe) içeren dizi için çalışacağını düşünüyorum .
jc

4

Son öğeyi bulmanın kolay yolu bu olmalıdır:

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

Referans: Bağlantı


- kopuk bağlantı -
T30

3

Bu "XY probleminin" kökünde OP'nin sadece implode()işlev görmek istediğine dair güçlü bir his var .


1
doğru. Ancak implodun o kadar pratik olmadığı durumlar vardır. Örneğin, içinde çok sayıda dinamik değişken içeren uzun bir html dizisi yerleştirmeye çalıştığınızı düşünün. Elbette, üzerinde bir ob_start / ob_get_clean yapabilir veya sadece $ str = '...' olarak oluşturabilirsiniz. Ancak, bunun sadece biraz aşırı bir sayı olarak kabul edilebileceği zamanlar vardır
Alastair Brayne

3

EOF dizisini bulma niyetiniz sadece tutkal içindir. Aşağıdaki taktik tanıtılın. EOF'a ihtiyacınız yoktur:

$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

Kulağa şöyle bir şey istiyormuşsunuz gibi geliyor:

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

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

2
Değerin kullanılması genellikle iyi bir fikir değildir, çünkü dizi iki özdeş değere sahipse düzgün çalışmaz.
orrd

2

Son değerden sonra virgül eklemeyin:

Dizi:

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

İşlev:

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

Sonuç:

print $result;

lorem, ipsum, dolor, oturmak, amet


1

bir count () yapabilirsiniz.

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

veya SADECE son elemanı arıyorsanız end () öğesini kullanabilirsiniz.

end(arr);

yalnızca son öğeyi döndürür.

ve ortaya çıktığı gibi, php dizilerini tamsayılarla endeksleyebilirsiniz. İle çok mutlu

arr[1];

1
Sonunda dezavantajı (dizi) dizinin dahili işaretçisini son öğeye ayarlar ..
Vijay

Hayır, GİRMEMELİ Anahtarlar sayısal ve sıralı olduklarını bilmedikçe diziler erişmek için tamsayılar kullanırlar. Düşünün: $a = array(0=>'A', 2=>'B', 'aaa'=>'C'). Erişirseniz ne elde edersiniz $a[count($a)-1]?
johndodo

1

Bunun gibi bir şey de yapabilirsiniz:

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

     // more code
}

end, diziyi değil değeri döndürür, böylece yaptığınız yol çalışmaz. dize karşılaştırması da tam sayıdan daha yavaştır.
OIS

Haklısın. son olmalı ($ element); $ endKey = anahtar ($ elements);
KOGI

1

Oldukça düzenli olduğunu düşündüğüm için aşağıdaki gibi. Diyelim ki tüm öğeler arasında ayırıcılar olan bir dize oluşturuyoruz: örneğin a, b, c

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

önce $ bildirmeden daha basit hale getirin; foreach ($ item $ key => $ item olarak) sonra $ 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>";

}

Referans


0

İşte bunu yapmanın başka bir yolu:

$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

Seni anlıyorsam, o zaman tek gereken diziyi tersine çevirmek ve bir pop komutu ile son elemanı almak:

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);

0

Sorgunuzu yapmak için de bunu deneyebilirsiniz ... burada INSERT ile gösterilmiştir

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

SQL sorgusu üreten komut dosyaları veya ilk veya son öğeler için farklı bir işlem yapan herhangi bir şey için, gereksiz değişken denetimleri kullanmaktan kaçınmak çok daha hızlıdır (neredeyse iki kat daha hızlıdır).

Kabul edilen geçerli çözüm, döngü içinde bir döngü ve her_single_iteration yapılacak bir denetim kullanır, bunu yapmanın doğru (hızlı) yolu aşağıdaki gibidir:

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

Küçük bir ev yapımı kriter şunları gösterdi:

test1: model morg 100000 çalışır

zaman: 1869.3430423737 milisaniye

test2: 100000 model son çalışırsa

zaman: 3235.6359958649 milisaniye


0

Gitmenin bir başka yolu, önceki döngü döngüsü sonucunu hatırlamak ve bunu sonuç olarak kullanmaktır:

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

0

Ben şahsen html <ul> ve <li> elemanları ile kolay kullanım sağlayan bu tür bir yapı kullanıyorum: sadece başka bir mülk için eşitliği değiştirin ...

Dizi yanlış öğeler içeremez ancak false boolean içine dökülen diğer tüm öğeleri içerir.

$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

Son dizini dirctly alabilirsiniz:

$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

İşte benim çözümüm: Dizinizin sayısını (eksi 1) alın (0'da başladığından beri).

$lastkey = count($array) - 1;
foreach($array as $k=>$a){
    if($k==$lastkey){
        /*do something*/
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.