Tìm phần tử cuối cùng của một mảng trong khi sử dụng vòng lặp foreach trong PHP


215

Tôi đang viết một trình tạo truy vấn SQL bằng cách sử dụng một số tham số. Trong Java, rất dễ dàng để phát hiện phần tử cuối cùng của một mảng từ bên trong vòng lặp for bằng cách chỉ kiểm tra vị trí mảng hiện tại với độ dài của mảng.

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

Trong PHP họ có các chỉ mục không nguyên để truy cập các mảng. Vì vậy, bạn phải lặp lại qua một mảng bằng vòng lặp foreach. Điều này trở nên có vấn đề khi bạn cần đưa ra một số quyết định (trong trường hợp của tôi để nối thêm hoặc / và tham số trong khi xây dựng truy vấn).

Tôi chắc chắn phải có một số cách tiêu chuẩn để làm điều này.

Làm thế nào để bạn giải quyết điều này trong PHP?


2
Bạn đang cố gắng xác định xem bạn nên ghép "VÀ" hoặc "HOẶC" giữa các phần của mệnh đề where?
Darryl Hein

1
chỉ cần chỉ ra rằng bạn nên lưu trữ tổng số trong một biến thay vì gọi một phương thức cho mỗi lần lặp. for (int i = 0, int t = Array.length; i <t; i ++).
OIS


Hãy xem giải pháp này: stackoverflow.com/a/29474468/1478566
vbarbarosh

Câu trả lời:


313

Có vẻ như bạn muốn một cái gì đó như thế này:

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

Điều đó đang được nói, bạn không - phải lặp đi lặp lại một "mảng" bằng cách sử dụng foreachtrong php.


Tôi nghĩ rằng tôi sẽ đi cho giải pháp này vì nó gần giống với mã tôi đã đăng. Ngay cả câu trả lời của Jeremy cũng phù hợp nhưng tôi nghĩ nó hơi phức tạp so với câu trả lời này. Tôi chưa chạy thử nghiệm nào nhưng tôi đoán câu trả lời này sẽ nhanh hơn vì nó không trích xuất được các phím. Điều này sẽ có tốc độ O (1)
Vaibhav Kamble

18
$numItems = count($arr)thủ thuật là không cần thiết và làm giảm khả năng đọc - trong PHP không có hình phạt hiệu năng cho việc truy cập số lượng ($ Array) mỗi lần. Lý do là số lượng vật phẩm được lưu bên trong dưới dạng trường đặc biệt trong tiêu đề mảng và không được tính khi đang di chuyển. Thủ thuật này đến từ các ngôn ngữ khác (C, Java ?, ...).
johndodo

7
Điều đó thật thú vị @johndodo rằng không có hình phạt về hiệu suất khi truy cập số lượng ($ Array) mỗi lần. Bạn có bất kỳ liên kết / nguồn đến nơi tối ưu hóa cụ thể này được ghi lại? Cảm ơn!
zuallauz

2
Thật đáng buồn khi trong PHP, giải pháp đúng đắn nhất cho vấn đề này có vẻ không phù hợp :(
kizzx2

1
@tomsihap $ i cần được tăng lên trong vòng lặp, song song với phép lặp mảng. $ i cần biểu diễn số lượng vật phẩm trong mảng, để nó có thể được sử dụng để xác định thời điểm đạt được mục cuối cùng. Nếu không có ++, vòng lặp sẽ chỉ so sánh "0" với tổng số mục.
Bobby Jack

201

Bạn có thể lấy giá trị của khóa cuối cùng của mảng bằng cách sử dụng end(array_keys($array))và so sánh nó với khóa hiện tại:

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

2
+1 Tôi đồng ý - các giải pháp khác dựa vào mảng có chỉ mục số.
Patrick Glandien

19
Để tự vệ, câu trả lời của tôi không phụ thuộc vào mảng có các phím số :)
Richard Levasseur

2
so sánh chuỗi chậm hơn số nguyên và không phải lúc nào cũng chính xác khi so sánh chuỗi với số nguyên (ít nhất bạn nên sử dụng ===). Tôi bỏ phiếu này xuống.
OIS

4
nó thanh lịch, nhưng gây ra THÔNG BÁO CHIẾN LƯỢC vì "kết thúc" mong đợi một giá trị tham chiếu :(
Wiliam

10
Khắc phục cho THÔNG BÁO CHIẾN LƯỢC:$lastKey = array_search(end($array), $array);
Ajax

44

sao phức tạp vậy

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

Điều này sẽ thêm một, đằng sau mỗi giá trị ngoại trừ giá trị cuối cùng!


2
Không phải nếu đầu vào $ tiếp theo chứa giá trị boolean là false, đây là một vấn đề lớn với next ().
soulseekah

29
Trừ khi tôi nhầm, điều này không hoạt động vì việc gọi next () tiến bộ con trỏ mảng, vì vậy bạn bỏ qua mọi phần tử khác trong vòng lặp.
Jordan Lev

2
Dường như không làm việc cho tôi. Phần tử cuối cùng thứ hai không nhận được dấu phẩy nhưng nó nên.
zuallauz

1
Nếu giá trị tương đương với bool false thì nó không hoạt động. Cũng không in dấu phẩy cuối cùng giữa giá trị thứ hai đến giá trị cuối cùng.
OIS

1
Một lưu ý cho bất kỳ ai muốn sử dụng điều này trong PHP7 - con trỏ mảng không di chuyển trong các vòng lặp foreach và điều này sẽ không hoạt động.
Scott Flack

26

Khi toEnd đạt 0, điều đó có nghĩa là nó ở lần lặp cuối cùng của vòng lặp.

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

Giá trị cuối cùng vẫn có sẵn sau vòng lặp, vì vậy nếu bạn chỉ muốn sử dụng nó cho nhiều thứ hơn sau vòng lặp thì điều này tốt hơn:

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

Nếu bạn không muốn coi giá trị cuối cùng là các vòng lặp đặc biệt bên trong. Điều này sẽ nhanh hơn nếu bạn có mảng lớn. (Nếu bạn sử dụng lại mảng sau vòng lặp bên trong cùng phạm vi, bạn phải "sao chép" mảng trước).

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

Và để trả lời câu hỏi ban đầu của bạn "trong trường hợp của tôi để nối hoặc / và tham số trong khi xây dựng truy vấn"; điều này sẽ lặp qua tất cả các giá trị, sau đó nối chúng lại với nhau thành một chuỗi có "và" giữa chúng nhưng không nằm trước giá trị đầu tiên hoặc sau giá trị cuối cùng:

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

2
Tất nhiên, nó sẽ thực hiện - $ toEnd cho mỗi lần lặp, đó là điểm chính. Nếu tôi di chuyển nó ra ngoài vòng lặp, nó sẽ không hoạt động nữa.
OIS

Phương pháp đơn giản nhất từng được sử dụng. $lastValue = array_pop($array);Cảm ơn bạn.
Elias Nicolas

21

Đã có nhiều câu trả lời, nhưng cũng đáng để xem xét các trình vòng lặp, đặc biệt là khi nó được yêu cầu một cách tiêu chuẩn:

$arr = range(1, 3);

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

Bạn cũng có thể tìm thấy một cái gì đó hoạt động linh hoạt hơn cho các trường hợp khác.


Câu trả lời chính xác. Tôi đánh giá cao rằng bạn đang sử dụng các tính năng của ngôn ngữ dành cho nhiệm vụ. i=0;++i;luôn luôn có vẻ hackish trong một ngôn ngữ kịch bản như PHP.
CheddarMonkey

15

Một cách có thể là phát hiện nếu iterator có next. Nếu không có phần tiếp theo được gắn vào iterator, điều đó có nghĩa là bạn đang ở vòng lặp cuối cùng.

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

Tôi nghĩ rằng đây là cách dễ nhất và yêu cầu số lượng mã ít nhất!
hi im zvaehn

1
Không hoạt động với PHP 7+ như "Trong PHP 7, foreach không sử dụng con trỏ mảng bên trong.".
Damien Debin

8

Vì vậy, nếu mảng của bạn có các giá trị mảng duy nhất, thì việc xác định lần lặp cuối cùng là không đáng kể:

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

Như bạn thấy, điều này hoạt động nếu phần tử cuối cùng xuất hiện chỉ một lần trong mảng, nếu không bạn sẽ nhận được báo động sai. Trong đó không phải là, bạn phải so sánh các phím (chắc chắn là duy nhất).

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

Cũng lưu ý các nhà điều hành coparision nghiêm ngặt, điều này khá quan trọng trong trường hợp này.


Đây là cách khá không hiệu quả.
Ý thức chung của bạn

Không. Không phải vậy. end () thực hiện O (1). Nó cũng ngắn hơn các giải pháp khác và nó đọc ra độc đáo -> Nếu phần tử bằng cuối của mảng, hãy viết "Lần cuối".
Rok Kralj

Điều này chậm hơn gấp đôi so với các ví dụ đầu tiên và cuối cùng của tôi cho 100000 giá trị.
OIS

5

Giả sử bạn có mảng được lưu trữ trong một biến ...

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

Điều này rất đơn giản và hữu ích. Tôi sẽ chỉ đếm mảng đầu tiên bên ngoài vòng lặp foreach để chương trình sẽ không phải đếm mỗi khi hàm foreach đánh giá từng mục.
Pathros 18/2/2015

3
Điều này sẽ không làm việc trên các mảng kết hợp. $ key không phải lúc nào cũng là một số.
Jonathan

5

để có được phần tử đầu tiên và cuối cùng từ mảng foreach

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

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

4

Bạn vẫn có thể sử dụng phương pháp đó với các mảng kết hợp:

$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
Vui lòng thay đổi $ key = $ mảng [$ i]; đến $ key = $ key [$ i]; trong vòng lặp đầu tiên.
Narek

4

Nếu bạn cần làm gì đó cho mọi phần tử ngoại trừ phần tử đầu tiên hoặc phần tử cuối cùng và chỉ khi có nhiều phần tử trong mảng, tôi thích giải pháp sau.

Tôi biết có nhiều giải pháp ở trên và được đăng vài tháng / một năm trước tôi, nhưng đây là điều tôi cảm thấy khá thanh lịch theo đúng nghĩa của nó. Kiểm tra mỗi vòng lặp cũng là một kiểm tra boolean trái ngược với kiểm tra "i = (đếm-1)" số, có thể cho phép ít chi phí hơn.

Cấu trúc của vòng lặp có thể cảm thấy khó xử, nhưng bạn có thể so sánh nó với thứ tự của thead (bắt đầu), t feet (kết thúc), tbody (hiện tại) trong các thẻ bảng 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;
}

Chẳng hạn, trong các thuật ngữ phát triển web, nếu bạn muốn thêm phần dưới cùng cho mọi phần tử ngoại trừ phần tử cuối cùng trong danh sách không có thứ tự (ul), thì bạn có thể thêm phần viền trên cho mọi phần tử trừ phần tử đầu tiên (CSS: con đầu lòng, được hỗ trợ bởi IE7 + và Firefox / Webkit hỗ trợ logic này, trong khi: con cuối không được IE7 hỗ trợ).

Bạn có thể thoải mái sử dụng lại biến $ đầu tiên cho mỗi vòng lặp lồng nhau và mọi thứ sẽ hoạt động tốt vì mỗi vòng lặp làm cho $ đầu tiên sai trong quá trình lặp đầu tiên (do đó, phá vỡ / ngoại lệ sẽ không gây ra vấn đề) .

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

Ví dụ đầu ra:

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)

Thanx, đây là giải pháp yêu thích của tôi! Nó rất linh hoạt và chi phí chỉ là một boolean. BTW, tôi nghĩ rằng điều này sẽ làm việc cho mảng chứa ít nhất một phần tử (không chỉ nhiều hơn một phần tử).
jc

4

Đây phải là cách dễ dàng để tìm phần tử cuối cùng:

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

Tham khảo: Liên kết


- liên kết bị hỏng -
T30

3

Tôi có một cảm giác mạnh mẽ rằng tại gốc rễ của "vấn đề XY" này, OP chỉ muốn implode()hoạt động.


1
thật. Có những trường hợp mặc dù implode chỉ là không thực tế. Ví dụ, hãy tưởng tượng bạn đang cố gắng tạo ra một chuỗi html dài với rất nhiều biến động trong đó. Chắc chắn, bạn có thể thực hiện ob_start / ob_get_clean trên nó hoặc chỉ xây dựng nó dưới dạng $ str = '...'. Nhưng, có những lúc điều này có thể được coi là một sự quá mức cần thiết
Alastair Brayne

3

Như ý định của bạn để tìm mảng EOF chỉ là cho keo. Được giới thiệu về chiến thuật dưới đây. Bạn không cần yêu cầu 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

Có vẻ như bạn muốn một cái gì đó như thế này:

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

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

2
Sử dụng giá trị thường không phải là một ý tưởng tốt bởi vì nó sẽ không hoạt động đúng nếu mảng có hai giá trị giống nhau.
orrd

2

Không thêm dấu phẩy sau giá trị cuối cùng:

Mảng:

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

Chức năng:

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

Kết quả:

print $result;

lorem, ipsum, dolor, ngồi, amet


1

bạn có thể làm một số đếm ().

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

hoặc nếu bạn đang tìm kiếm CHỈ phần tử cuối cùng, bạn có thể sử dụng end ().

end(arr);

chỉ trả về phần tử cuối cùng.

và, hóa ra, bạn CÓ THỂ lập chỉ mục các mảng php theo số nguyên. Nó hoàn toàn hài lòng với

arr[1];

1
Hạn chế cuối cùng (mảng) là nó đặt con trỏ bên trong của mảng thành phần tử cuối cùng ..
Vijay

Không, bạn KHÔNG NÊN sử dụng số nguyên để truy cập các mảng trừ khi bạn biết rằng các khóa là số và tuần tự. Hãy xem xét : $a = array(0=>'A', 2=>'B', 'aaa'=>'C'). Bạn nhận được gì nếu bạn truy cập $a[count($a)-1]?
johndodo

1

Bạn cũng có thể làm một cái gì đó như thế này:

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

     // more code
}

end trả về giá trị không phải là mảng, vì vậy cách bạn thực hiện nó không hoạt động. chuỗi so sánh cũng chậm hơn số nguyên.
OIS

Bạn đúng rồi. nó nên kết thúc ($ phần tử); $ endKey = key ($ phần tử);
KOGI

1

Tôi giống như sau đây vì tôi cảm thấy nó khá gọn gàng. Giả sử chúng ta đang tạo một chuỗi có dấu phân cách giữa tất cả các phần tử: ví dụ a, b, c

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

làm cho nó đơn giản hơn mà không cần khai báo $ trước; sử dụng foreach ($ item as $ key => $ item) rồi $ 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>";

}

Tài liệu tham khảo


0

Đây là một cách khác bạn có thể làm điều đó:

$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

Nếu tôi hiểu bạn, thì tất cả những gì bạn cần là đảo ngược mảng và lấy phần tử cuối cùng bằng lệnh pop:

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);

0

Bạn cũng có thể thử điều này để thực hiện truy vấn của mình ... được hiển thị ở đây với 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

Đối với các tập lệnh tạo truy vấn SQL hoặc bất kỳ tập lệnh nào thực hiện hành động khác cho các phần tử đầu tiên hoặc cuối cùng, sẽ nhanh hơn nhiều (gần gấp đôi nhanh) để tránh sử dụng kiểm tra biến không cần thiết.

Giải pháp được chấp nhận hiện tại sử dụng một vòng lặp và kiểm tra trong vòng lặp sẽ được thực hiện every_single_iteration, cách chính xác (nhanh) để làm điều này là như sau:

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

Một chút điểm chuẩn tự chế cho thấy như sau:

test1: 100000 lần chạy mô hình

thời gian: 1869.3430423737 mili giây

test2: 100000 lần chạy mô hình nếu kéo dài

thời gian: 3235.6359958649 mili giây


0

Một cách khác để nhớ là kết quả vòng lặp trước đó và sử dụng kết quả cuối cùng:

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

0

Cá nhân tôi sử dụng loại xây dựng này cho phép sử dụng dễ dàng với các phần tử <ul> và <li> html: chỉ cần thay đổi đẳng thức cho một thuộc tính khác ...

Mảng không thể chứa các mục sai nhưng tất cả các mục khác được chuyển thành boolean sai.

$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

Bạn có thể dirctly lấy chỉ số cuối cùng bằng cách:

$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

Đây là giải pháp của tôi: Đơn giản chỉ cần đếm số mảng của bạn, trừ 1 (vì chúng bắt đầu bằng 0).

$lastkey = count($array) - 1;
foreach($array as $k=>$a){
    if($k==$lastkey){
        /*do something*/
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.