Bagaimana menentukan iterasi pertama dan terakhir dalam loop foreach?

494

Pertanyaannya sederhana. Saya memiliki foreachloop dalam kode saya:

foreach($array as $element) {
    //code
}

Dalam loop ini, saya ingin bereaksi secara berbeda ketika kita berada dalam iterasi pertama atau terakhir.

Bagaimana cara melakukannya?

mehdi
sumber

Jawaban:

426

Anda bisa menggunakan penghitung:

$i = 0;
$len = count($array);
foreach ($array as $item) {
    if ($i == 0) {
        // first
    } else if ($i == $len - 1) {
        // last
    }
    // …
    $i++;
}
Gumbo
sumber
24
Saya tidak berpikir downvoting harus dilakukan di sini karena ini juga berfungsi dengan benar dan masih tidak begitu sampah menggunakan array_shiftdan array_pop. Meskipun ini adalah solusi yang saya temukan jika saya harus menerapkan hal seperti itu, saya akan tetap dengan jawaban Rok Kralj sekarang.
shadyyx
15
Jika saya membutuhkan penghitung, maka saya lebih suka menggunakan FOR loop daripada FOREACH.
rkawano
10
Jika Anda menggunakan $i = 1, Anda tidak perlu khawatir $len - 1, cukup gunakan $len.
aksu
2
@Wan Bagaimana poin # 3 benar? Atau relevan dengan pertanyaan ini karena melibatkan HTML? Ini adalah pertanyaan PHP, jelas ... dan ketika datang untuk menandai semantik, itu adalah fakta yang jauh lebih dalam daripada "blahblah yang tepat selalu lebih baik daripada blahblah (ini bahkan bukan pendapat saya, itu fakta murni)"
Deji
1
@rkawano tetapi Anda tidak bisa mendapatkan kunci yang disebutkan jika Anda menggunakan FOR loop
Fahmi
1015

Jika Anda lebih suka solusi yang tidak memerlukan inisialisasi penghitung di luar loop, saya mengusulkan membandingkan kunci iterasi saat ini terhadap fungsi yang memberitahu Anda kunci terakhir / pertama dari array.

Ini menjadi lebih efisien (dan lebih mudah dibaca) dengan PHP 7.3 yang akan datang.

Solusi untuk PHP 7.3 dan lebih tinggi:

foreach($array as $key => $element) {
    if ($key === array_key_first($array))
        echo 'FIRST ELEMENT!';

    if ($key === array_key_last($array))
        echo 'LAST ELEMENT!';
}

Solusi untuk semua versi PHP:

foreach($array as $key => $element) {
    reset($array);
    if ($key === key($array))
        echo 'FIRST ELEMENT!';

    end($array);
    if ($key === key($array))
        echo 'LAST ELEMENT!';
}
Rok Kralj
sumber
44
Jawaban yang fantastis! Jauh lebih bersih daripada menggunakan banyak array.
Paul J
14
Ini akan menggelembung sampai ke puncak karena itu adalah jawaban yang tepat. Keuntungan lain dari fungsi-fungsi ini daripada menggunakan array_shift dan array_pop adalah bahwa array dibiarkan utuh, jika mereka diperlukan pada titik selanjutnya. +1 untuk berbagi pengetahuan hanya demi hal itu.
Awemo
13
ini jelas cara terbaik jika Anda ingin menjaga kode Anda tetap bersih. Saya hendak melakukan upvote, tapi sekarang saya tidak yakin overhead fungsional dari metode array itu sepadan. Jika kita hanya berbicara tentang elemen terakhir maka itu adalah end()+ key()atas setiap iterasi dari loop - jika keduanya maka itu 4 metode yang dipanggil setiap waktu. Memang, itu akan menjadi operasi yang sangat ringan dan mungkin hanya penunjuk penunjuk, tetapi kemudian dokumen akan menentukan reset()dan end() memodifikasi penunjuk internal array - jadi apakah ini lebih cepat daripada penghitung? mungkin juga tidak.
pospi
19
Saya tidak berpikir Anda harus mengeluarkan reset ($ array) di dalam foreach. Dari dokumentasi resmi (www.php.net/foreach): "Karena foreach bergantung pada pointer array internal mengubahnya dalam loop dapat menyebabkan perilaku yang tidak terduga." Dan mengatur ulang tidak tepat itu (www.php.net/reset): "Atur pointer internal array ke elemen pertama"
Gonçalo Queirós
11
@ GonçaloQueirós: Berhasil. Foreach bekerja pada salinan array. Namun, jika Anda masih khawatir, jangan ragu untuk memindahkan reset()panggilan sebelum pemeriksaan dan cache hasilnya $first.
Rok Kralj
121

Untuk menemukan item terakhir, saya menemukan kode ini berfungsi setiap saat:

foreach( $items as $item ) {
    if( !next( $items ) ) {
        echo 'Last Item';
    }
}
Yojance
sumber
2
Ini memiliki terlalu sedikit upvotes, apakah ada kelemahan menggunakan ini?
Kevin Kuyl
2
@Kevin Kuyl - Seperti disebutkan oleh Pang di atas, jika array berisi item yang PHP anggap salah (yaitu 0, "", null) metode ini akan mendapatkan hasil yang tidak terduga. Saya telah mengubah kode untuk menggunakan ===
Eric Kigathi
4
ini sebagian besar sangat mengagumkan tetapi untuk memperjelas masalah yang orang lain tunjukkan itu akan selalu gagal dengan array seperti [true,true,false,true]. Tetapi secara pribadi saya akan menggunakan ini kapan saja saya berurusan dengan array yang tidak mengandung boolean false.
billynoah
4
next()harus TIDAK PERNAH digunakan di dalam foreach loop. Ini mengacaukan pointer array internal. Lihatlah dokumentasi untuk informasi lebih lanjut.
Drazzah
89

Versi yang lebih disederhanakan di atas dan menganggap Anda tidak menggunakan indeks khusus ...

$len = count($array);
foreach ($array as $index => $item) {
    if ($index == 0) {
        // first
    } else if ($index == $len - 1) {
        // last
    }
}

Versi 2 - Karena saya telah membenci menggunakan yang lain kecuali diperlukan.

$len = count($array);
foreach ($array as $index => $item) {
    if ($index == 0) {
        // first
        // do something
        continue;
    }

    if ($index == $len - 1) {
        // last
        // do something
        continue;
    }
}
Hayden
sumber
8
Ini juga berfungsi untuk objek. Solusi lain hanya berfungsi untuk array.
Lamy
1
Ini adalah jawaban terbaik untuk saya tetapi harus dipadatkan, tidak ada titik yang menyatakan panjang di luar loop foreach: if ($ index == count ($ array) -1) {...}
Andrew
2
@Andrew dengan cara itu Anda terus menghitung elemen array, untuk setiap iterasi.
pcarvalho
1
@peteroak Ya sebenarnya itu secara teknis akan merusak kinerja, dan tergantung apa yang Anda hitung atau berapa banyak loop yang signifikan. Jadi abaikan komentar saya: D
Andrew
4
@peteroak @Andrew Jumlah total elemen dalam array disimpan sebagai properti secara internal, jadi tidak akan ada hit kinerja dengan melakukan if ($index == count($array) - 1). Lihat di sini .
GreeKatrina
36

Anda bisa menghapus elemen pertama dan terakhir dari array dan memprosesnya secara terpisah.

Seperti ini:

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

Menghapus semua pemformatan ke CSS alih-alih tag inline akan meningkatkan kode Anda dan mempercepat waktu pemuatan.

Anda juga dapat menghindari pencampuran HTML dengan logika php bila memungkinkan.

Halaman Anda dapat dibuat lebih mudah dibaca dan dikelola dengan memisahkan hal-hal seperti ini:

<?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
}
?>
Carlos Lima
sumber
20

Upaya untuk menemukan yang pertama adalah:

$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
  }
}
sstauross
sumber
3
Harap edit jawaban Anda untuk menambahkan penjelasan tentang cara kerja kode Anda dan cara memecahkan masalah OP. Banyak poster SO adalah pemula dan tidak akan mengerti kode yang telah Anda posting.
Saya khawatir alien
4
Jawaban ini tidak mengatakan bagaimana menentukan apakah Anda berada di iterasi terakhir dari loop. Namun, ini merupakan upaya yang sah untuk jawaban, dan tidak boleh ditandai sebagai bukan jawaban. Jika Anda tidak menyukainya, Anda harus memilihnya, bukan memilihnya.
ArtOfWarfare
Jelas, dalam iterasi pertama ia akan memasuki kondisi pertama dan kemudian mengubahnya nilainya menjadi false, dan dengan cara ini ia hanya akan masuk ke iterasi pertama sekali.
Mohamed23gharbi
20

Cukup ini berhasil!

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

Terima kasih @billynoah untuk Anda memilah-milah masalah akhir .

Sydwell
sumber
3
Terbaik! Saya hanya akan mengklarifikasi if ($key === $lastkey).
Krzysztof Przygoda
2
bukankah ini seharusnya if ($lastkey === $key)?
Kinetic
1
Saya mendapatkan:PHP Warning: key() expects parameter 1 to be array, integer given in php shell code on line 1
billynoah
1
@Sydwell - baca kesalahannya. key()mendapatkan bilangan bulat, bukan end(). end()" mengembalikan nilai elemen terakhir ", dan key()mengharapkan array sebagai input.
billynoah
11

1: Mengapa tidak menggunakan forpernyataan sederhana ? Dengan asumsi Anda menggunakan array nyata dan bukan IteratorAnda dapat dengan mudah memeriksa apakah variabel penghitung adalah 0 atau kurang dari jumlah seluruh elemen. Menurut pendapat saya ini adalah solusi yang paling bersih dan dapat dimengerti ...

$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: Anda harus mempertimbangkan untuk menggunakan Nested Sets untuk menyimpan struktur pohon Anda. Selain itu Anda dapat meningkatkan semuanya dengan menggunakan fungsi rekursif.

okoman
sumber
Jika Anda akan menggunakan, forAnda dapat loop dari 1ke n-1dan mengambil ifs keluar dari tubuh. Tidak ada gunanya memeriksanya berulang kali.
mpen
9

Jawaban Terbaik:

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

}
Ivan
sumber
2
Ini gagal ketika Anda hanya memiliki satu elemen dalam array.
Memochipan
4
Ini cepat dan mudah selama Anda bisa memastikan selalu ada lebih dari satu semen dalam array (seperti kata Memochipan). Jadi itu bukan solusi yang gagal bagi saya - tidak ada 'jawaban terbaik'.
Seika85
5
masing-masing () akan DIPRESEKSI pada PHP 7.2.0 . Silakan juga melihat php.net/manual/en/function.each.php
Flow
8

Jawaban paling efisien dari @morg, tidak seperti foreach, hanya berfungsi untuk array yang tepat, bukan objek peta hash. Jawaban ini menghindari overhead pernyataan bersyarat untuk setiap iterasi loop, seperti dalam sebagian besar jawaban ini (termasuk jawaban yang diterima) dengan secara khusus menangani elemen pertama dan terakhir, dan pengulangan ke elemen tengah.

The array_keysfungsi dapat digunakan untuk membuat jawaban kerja yang efisien seperti 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++;

Saya belum melakukan benchmark pada hal ini, tetapi tidak ada logika yang ditambahkan ke loop, yang merupakan hit terbesar untuk kinerja terjadi, jadi saya menduga bahwa tolok ukur yang diberikan dengan jawaban efisien cukup dekat.

Jika Anda ingin memfungsikan hal semacam ini, saya telah mengambil ayunan fungsi iterateList di sini . Meskipun, Anda mungkin ingin membandingkan kode inti jika Anda sangat memperhatikan efisiensi. Saya tidak yakin berapa banyak overhead semua fungsi yang diperkenalkan doa.

Pengembang Mad
sumber
6

Untuk skrip pembuatan kueri SQL, atau apa pun yang melakukan tindakan berbeda untuk elemen pertama atau terakhir, itu jauh lebih cepat (hampir dua kali lebih cepat) untuk menghindari menggunakan pemeriksaan variabel yang tidak perlu.

Solusi yang diterima saat ini menggunakan loop dan centang dalam loop yang akan dibuat every_single_iteration, cara (cepat) yang benar untuk melakukan ini adalah sebagai berikut:

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

Patokan kecil buatan sendiri menunjukkan yang berikut:

test1: 100000 menjalankan model morg

waktu: 1869,3430423737 milidetik

test2: 100000 menjalankan model jika bertahan

waktu: 3235.6359958649 milidetik

Dan dengan demikian cukup jelas bahwa biaya pemeriksaan banyak, dan tentu saja semakin buruk semakin banyak cek variabel yang Anda tambahkan;)

Morg.
sumber
Kode Anda hanya berfungsi jika Anda yakin harus memiliki kunci integer yang bertambah. $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++;akan menampilkan:0: , 1: One, 2: ,
Seika85
melempar peta hash ke array adalah perilaku yang tidak dapat ditentukan, "Objek" array()dibuat {'one':"1 1 1",0:"",1:"One",2:"",3:"",4:"Four"}tetapi elemen kosong diabaikan dengan hitungan, Anda menghitung jumlah "benda" yang ditentukan !! PENGHASILAN PENGORBANAN BOUNTY! Jawaban ini layak mendapat hadiah, tetapi jika @Morg. pergi, tidak ada gunanya. Saya akan memberikan hadiah kepada seseorang yang mungkin tidak akan menggunakan SO lagi! Jika dia kembali dan meningkatkan jawabannya, dia layak mendapatkan hadiah!
mjz19910
Seperti yang dicatat oleh @ mjz19910, peta dan array hash tidak dapat dipertukarkan. Namun, Anda bisa mendapatkan properti hash dengan array_keysfungsi, yang bisa Anda perlakukan seperti array. Lihat jawaban "ditingkatkan" saya .
TheMadDeveloper
Itulah yang saya gunakan untuk permintaan:$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'";
Rovshan Mamedov
5

Dengan Tombol dan Nilai ini berfungsi juga:

foreach ($array as $key => $value) {
    if ($value === end($array)) {
        echo "LAST ELEMENT!";
    }
}
Benibr
sumber
2
Dengan cara ini Anda membandingkan nilai dan tidak berfungsi jika array berisi dua elemen yang sama.
Krzysztof Przygoda
5

Menggunakan variabel Boolean masih yang paling dapat diandalkan, bahkan jika Anda ingin memeriksa tampilan pertama dari a $value (saya menemukan itu lebih berguna dalam situasi saya dan dalam banyak situasi) , seperti ini:

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

Lalu bagaimana !next( $array )menemukan yang terakhir $valueyang akan kembali truejika tidak ada next()nilai untuk beralih.

Dan saya lebih suka menggunakan forloop daripada foreachjika saya akan menggunakan penghitung, seperti ini:

$len = count( $array );
for ( $i = 0; $i < $len; $i++ ) {
    $value = $array[$i];
    if ($i === 0) {
        // first
    } elseif ( $i === $len - 1 ) {
        // last
    }
    // …
    $i++;
}
5ervant
sumber
4

Saya menemukan utas ini ketika saya memiliki masalah yang sama. Saya hanya perlu mendapatkan elemen pertama kemudian saya menganalisis ulang kode saya sampai ini muncul di pikiran saya.

$firstElement = true;

foreach ($reportData->result() as $row) 
{
       if($firstElement) { echo "first element"; $firstElement=false; }
       // Other lines of codes here
}

Kode di atas bagus dan lengkap tetapi jika Anda hanya perlu elemen pertama maka Anda dapat mencoba kode ini.

paul
sumber
2

Tidak yakin apakah itu masih perlu. Tetapi solusi berikut harus bekerja dengan iterator dan tidak memerlukan 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;
        }
    }
}
vbarbarosh
sumber
0

Anda juga dapat menggunakan fungsi anonim:

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

Tiga hal lagi harus disebutkan:

  • Jika array Anda tidak diindeks secara ketat (secara numerik) Anda harus mem-pipe array Anda array_valuesterlebih dahulu.
  • Jika Anda perlu memodifikasi, $elementAnda harus meneruskannya dengan referensi ( &$element).
  • Setiap variabel dari luar fungsi anonim yang Anda butuhkan di dalam, Anda harus mencantumkannya di sebelah $indexOfLastElementdalam usekonstruk, lagi dengan referensi jika diperlukan.
undko
sumber
0

Anda dapat menggunakan penghitung dan panjang array.

    $ array = array (1,2,3,4);

    $ i = 0;
    $ len = count ($ array);
    foreach ($ array sebagai $ item) {
        if ($ i === 0) {
            // pertama
        } lain jika ($ i === $ len - 1) {
            // terakhir
        }
        // ...
        $ i ++;
    }
Yesus Erwin Suarez
sumber
0
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();
   }
}
Joao Paulo Pinheiro
sumber
0

Menggunakan reset ($ array) dan 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>";
        }                

    }

Demo repl.it

antelove
sumber
-2

Coba ini:

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