PHP에서 foreach 루프를 사용하는 동안 배열의 마지막 요소 찾기


215

일부 매개 변수를 사용하여 SQL 쿼리 작성자를 작성 중입니다. Java에서는 배열 길이로 현재 배열 위치를 확인하면 for 루프 내부에서 배열의 마지막 요소를 매우 쉽게 감지 할 수 있습니다.

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

PHP에서는 배열에 액세스하기 위해 정수가 아닌 인덱스를 가지고 있습니다. 따라서 foreach 루프를 사용하여 배열을 반복해야합니다. 이것은 어떤 결정을 내려야 할 때 문제가됩니다 (제 경우에는 쿼리를 작성하는 동안 추가 또는 매개 변수).

이 작업을 수행하는 표준 방법이 있어야합니다.

PHP에서 어떻게 해결합니까?


2
where 절의 일부 사이에 "AND"또는 "OR"을 연결해야하는지 여부를 결정하려고합니까?
Darryl Hein

1
모든 반복마다 메소드를 호출하는 대신 총계를 변수에 저장해야한다고 지적했습니다. for (int i = 0, int t = arr.length; i <t; i ++).
OIS


이 솔루션을 살펴보십시오 : stackoverflow.com/a/29474468/1478566
vbarbarosh

답변:


313

다음과 같이 원하는 것처럼 들립니다.

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

즉, foreachPHP에서 사용하는 "배열"을 반복하지는 않습니다 .


이 솔루션은 내가 게시 한 코드와 거의 유사 하므로이 솔루션을 사용한다고 생각합니다. Jeremy의 대답조차도 적합하지만 이것에 비해 조금 복잡하다고 생각합니다. 나는 어떤 테스트도 실행하지 않았지만 키의 배열을 추출하지 않기 때문에이 답변이 더 빠를 것이라고 생각합니다. 이것은 O (1) 속도를
가져야합니다

18
$numItems = count($arr)트릭이 필요하지 않고 가독성이 떨어집니다. PHP에서는 매번 count ($ arr)에 액세스 할 때 성능이 저하되지 않습니다. 그 이유는 항목 개수가 내부적으로 배열 헤더에 특수 필드로 저장되어 즉시 계산 되지 않기 때문 입니다. 이 트릭은 다른 언어 (C, Java?, ...)에서 나옵니다.
johndodo

7
흥미로운 @johndodo는 매번 count ($ arr)에 액세스 할 때 성능 저하가 없다는 것입니다. 이 특정 최적화가 문서화되어있는 링크 / 소스가 있습니까? 감사!
zuallauz

2
PHP에서이 문제에 대한 가장 정확한 해결책이 다소 우아하지
않다는

1
@tomsihap $ i는 배열 반복과 함께 루프 내에서 증가해야합니다. $ i는 마지막 항목에 도달 한 시점을 결정하는 데 사용할 수 있도록 배열의 항목 수를 나타내야합니다. ++가 없으면 루프는 "0"만 총 항목 수와 비교합니다.
Bobby Jack

201

배열의 마지막 키 값을 사용 end(array_keys($array))하여 현재 키와 비교할 수 있습니다.

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

2
+1 동의합니다-다른 솔루션은 숫자 인덱스가있는 배열에 의존합니다.
Patrick Glandien

19
내 자신의 방어, 내 대답은 숫자 키를 가진 배열에 의존하지 않습니다 :)
Richard Levasseur

2
문자열 비교는 정수보다 느리고 문자열을 정수와 비교할 때 항상 정확하지는 않습니다 (적어도 ===를 사용해야합니다). 이걸 투표하고 있어요
OIS

4
우아하지만, "끝"이 참조 값을 기대하기 때문에 엄격한 통지를 유발합니다 :(
Wiliam

10
엄격한 통지에 대한 수정 :$lastKey = array_search(end($array), $array);
Ajax

45

왜 그렇게 복잡한가?

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

마지막 값을 제외한 모든 값 뒤에을 추가합니다!


2
다음 $ input에 부울 값 false가 포함되어 있으면 next ()의 주요 문제점입니다.
soulseekah

29
내가 실수하지 않으면 next ()를 호출하면 배열 포인터가 앞당겨지기 때문에 작동하지 않으므로 루프의 다른 모든 요소를 ​​건너 뜁니다.
Jordan Lev

2
나를 위해 작동하지 않는 것 같습니다. 두 번째 마지막 요소는 쉼표를 얻지 못하지만 쉼표를 얻습니다.
zuallauz

1
값이 부울과 같으면 작동하지 않습니다. 또한 두 번째 값에서 마지막 값과 마지막 값 사이의 마지막 쉼표를 인쇄하지 않습니다.
OIS

1
PHP7에서 이것을 사용하려는 사람을위한 참고 사항-배열 포인터는 foreach 루프에서 움직이지 않으며 작동하지 않습니다.
Scott Flack

26

toEnd가 0에 도달하면 루프의 마지막 반복에 있음을 의미합니다.

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

마지막 값은 루프 후에도 계속 사용할 수 있으므로 루프 후에 더 많은 것을 위해 사용하려는 경우 더 좋습니다.

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

마지막 값을 특수 내부 루프로 취급하지 않으려는 경우. 배열이 큰 경우 더 빠릅니다. 동일한 범위 내에서 루프 후 배열을 재사용하는 경우 먼저 배열을 "복사"해야합니다.

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

그리고 원래 질문에 대답하기 위해 "제 경우에는 쿼리를 작성하는 동안 매개 변수를 추가하거나 추가 할 수 있습니다"; 이렇게하면 모든 값을 반복 한 다음 첫 번째 값 앞이나 마지막 값이 아닌 "와"사이에 "와"가있는 문자열로 결합합니다.

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

2
물론 모든 반복에 대해-$ toEnd를 수행합니다. 루프 밖으로 이동하면 더 이상 작동하지 않습니다.
OIS

가장 간단한 방법이 사용되었습니다. $lastValue = array_pop($array);감사합니다.
Elias Nicolas

21

이미 많은 답변이 있지만 특히 표준 방법으로 요청 된 경우 반복자를 살펴볼 가치가 있습니다.

$arr = range(1, 3);

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

다른 경우에도 더 유연하게 작동하는 것을 찾을 수 있습니다.


좋은 대답입니다. 작업에 사용되는 언어의 기능을 사용하고 있음을 알려드립니다. i=0;그리고 ++i;항상 PHP와 같은 스크립트 언어로 hackish 듯했다.
체다 몽키

15

한 가지 방법은 반복자가 가지고 있는지 감지하는 것 next입니다. 반복자에 다음에 연결되지 않은 경우 마지막 루프 상태임을 의미합니다.

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

나는 이것이 가장 쉬운 방법이라고 생각하며 가장 적은 양의 코드가 필요합니다!
안녕하세요 메신저 zvaehn

1
PHP 7+에서는 "PHP 7에서 foreach는 내부 배열 포인터를 사용하지 않습니다."와 같이 작동하지 않습니다.
Damien Debin

8

따라서 배열에 고유 한 배열 값이 있으면 마지막 반복을 결정하는 것이 쉽지 않습니다.

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

보시다시피, 마지막 요소가 배열에 한 번만 나타나는 경우 작동합니다. 그렇지 않으면 잘못된 경보가 발생합니다. 그것은 당신이 키를 비교할 필요는 없습니다 (확실히 독특합니다).

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

또한 엄격한 coparision 연산자를 참고하십시오.이 경우에는 매우 중요합니다.


이것은 매우 비효율적 인 방법입니다.
당신의 상식

아니. 그렇지 않습니다. end ()는 O (1)을 수행합니다. 또한 다른 솔루션보다 짧으며 잘 읽습니다-> 요소가 배열의 끝과 같으면 "마지막"이라고 씁니다.
Rok Kralj

이것은 100000 값에 대한 첫 번째와 마지막 예제보다 두 배 이상 느립니다.
OIS

5

배열에 변수가 저장되어 있다고 가정하면 ...

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

이것은 매우 간단하고 유용합니다. foreach 함수가 각 항목을 평가할 때마다 프로그램이 계산할 필요가 없도록 foreach 루프 외부에서 먼저 배열을 계산합니다.
Pathros

3
연관 배열에서는 작동하지 않습니다. $ key가 항상 숫자는 아닙니다.
조나단

5

foreach 배열에서 첫 번째 및 마지막 요소를 가져옵니다.

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

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

4

이 방법을 연관 배열과 함께 계속 사용할 수 있습니다.

$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
$ key = $ array [$ i];를 변경하십시오 ~ $ key = $ keys [$ i]; 첫 번째 for 루프에서.
Narek

4

첫 번째 또는 마지막을 제외한 모든 요소에 대해 무언가를 수행해야하고 배열에 하나 이상의 요소가있는 경우에만 다음 솔루션을 선호합니다.

나는 위의 많은 솔루션이 있고 내 전에 몇 달 / 1 년을 게시 한 것을 알고 있지만 이것은 그 자체로 상당히 우아하다고 느낍니다. 모든 루프 검사는 숫자 "i = (count-1)"검사와 달리 부울 검사이므로 오버 헤드를 줄일 수 있습니다.

루프의 구조는 어색 할 수 있지만 HTML 테이블 태그에서 thead (시작), tfoot (종료), tbody (현재)의 순서와 비교할 수 있습니다.

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

예를 들어, 웹 개발 용어 에서 정렬되지 않은 목록 (ul) 의 마지막 요소를 제외한 모든 요소에 테두리 아래쪽 을 추가하려는 경우 첫 번째 요소를 제외한 모든 요소에 테두리 위쪽을 추가 할 수 있습니다 (CSS : IE7 +에서 지원되는 첫 번째 자식 및 Firefox / Webkit은이 논리를 지원하지만 : last-child는 IE7에서 지원되지 않습니다).

중첩 루프마다 $ first 변수를 자유롭게 재사용 할 수 있으며 첫 번째 반복의 첫 번째 프로세스 중에 모든 루프가 $ first를 거짓으로 만들기 때문에 문제가 발생하지 않습니다. 따라서 중단 / 예외로 인해 문제가 발생하지 않습니다. .

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

출력 예 :

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)

감사합니다. 이것이 제가 가장 좋아하는 솔루션입니다! 매우 유연하며 부울 비용입니다. BTW, 내가 포함 된 배열이 의지 작업 생각 이상 도 (뿐만 아니라 하나 개의 요소 보다 하나 개의 요소).
jc

4

이것이 마지막 요소를 찾는 쉬운 방법이어야합니다.

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

참조 : 링크


- 깨진 링크 -
T30

3

나는이 "XY 문제"의 근원에서 OP가 단지 implode()기능 하기를 원한다는 강한 느낌을 가지고있다 .


1
진실. 임플로드가 실용적이지 않은 경우가 있습니다. 예를 들어, 많은 동적 변수가 포함 된 긴 html 문자열을 포함하려고한다고 상상해보십시오. 물론, ob_start / ob_get_clean을 수행하거나 $ str = '...'로 빌드 할 수 있습니다. 그러나 이것이 단지 약간의 과잉 인 것으로 간주 될 수있는 때가있다
Alastair Brayne

3

EOF 어레이를 찾으려는 의도는 접착제뿐입니다. 아래 전술을 소개하십시오. 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

다음과 같이 원하는 것처럼 들립니다.

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

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

2
배열에 두 개의 동일한 값이있는 경우 값이 제대로 작동하지 않으므로 일반적으로 값을 사용하는 것은 좋지 않습니다.
orrd

2

마지막 값 뒤에 쉼표를 추가하지 마십시오.

배열 :

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

함수:

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

결과:

print $result;

lorem, ipsum, dolor, 앉다, amet


1

count ()를 할 수 있습니다.

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

또는 마지막 요소 만 찾고 있다면 end ()를 사용할 수 있습니다.

end(arr);

마지막 요소 만 반환합니다.

그리고 결과적으로 PHP 배열을 정수로 색인 할 수 있습니다. 그것은 완벽하게 행복합니다

arr[1];

1
end (arr)의 단점은 배열의 내부 포인터를 마지막 요소로 설정한다는 것입니다.
Vijay

키가 숫자이고 순차적이라는 것을 알지 않는 한 정수를 사용하여 배열에 액세스 해서는 안됩니다 . 고려하십시오 : $a = array(0=>'A', 2=>'B', 'aaa'=>'C'). 액세스하면 무엇을 얻 $a[count($a)-1]습니까?
johndodo

1

다음과 같이 할 수도 있습니다 :

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

     // more code
}

end는 배열이 아닌 값을 반환하므로 사용자가 만든 방식으로 작동하지 않습니다. 문자열 비교도 정수보다 느립니다.
OIS

네 말이 맞아 end ($ elements) 여야합니다. $ endKey = 키 ($ 요소);
KOGI

1

나는 그것이 상당히 깔끔하다고 생각할 때 다음과 같은 것을 좋아합니다. 모든 요소 사이에 구분 기호가있는 문자열을 작성한다고 가정 해 봅시다 : 예 : a, b, c

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

$ first를 선언하지 않고 더 단순하게 만드십시오. foreach ($ items as $ key => $ item)를 사용한 다음 $ 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>";

}

참고


0

다른 방법으로 할 수 있습니다.

$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

내가 당신을 이해한다면, 필요한 것은 배열을 뒤집고 pop 명령으로 마지막 요소를 얻는 것입니다.

   $rev_array = array_reverse($array);

   echo array_pop($rev_array);

0

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

SQL 쿼리 생성 스크립트 또는 첫 번째 요소 나 마지막 요소에 대해 다른 작업을 수행하는 작업의 경우 불필요한 변수 검사를 사용하지 않는 것이 훨씬 빠릅니다 (거의 두 배 빠름).

현재 허용되는 솔루션은 루프와 루프 내에서 점검을 사용하여 every_single_iteration이 수행되도록하는 올바른 (빠른) 방법은 다음과 같습니다.

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

작은 수제 벤치 마크는 다음을 보여주었습니다.

test1 : 모델 morg의 100000 실행

시간 : 1869.3430423737 밀리 초

test2 : 마지막 경우 100000 회 실행

시간 : 3235.6359958649 밀리 초


0

또 다른 방법은 이전 루프 사이클 결과를 기억하고 최종 결과로 사용하는 것입니다.

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

0

나는 개인적으로 html <ul> 및 <li> 요소와 함께 쉽게 사용할 수있는 이런 종류의 구성을 사용합니다 : 단순히 다른 속성의 평등을 변경하십시오 ...

배열은 잘못된 항목을 포함 할 수 없지만 잘못된 부울로 캐스트 된 다른 모든 항목을 포함 할 수 있습니다.

$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

다음과 같은 방법으로 마지막 색인을 얻을 수 있습니다.

$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

내 해결책은 다음과 같습니다. 간단히 배열의 개수에서 빼기 1을 뺍니다 (0부터 시작하기 때문에).

$lastkey = count($array) - 1;
foreach($array as $k=>$a){
    if($k==$lastkey){
        /*do something*/
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.