foreach 루프에서 첫 번째와 마지막 반복을 결정하는 방법은 무엇입니까?


494

질문은 간단합니다. 나는이 foreach내 코드에서 루프를 :

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

이 루프에서는 처음 또는 마지막 반복에있을 때 다르게 반응하고 싶습니다.

이것을하는 방법?

답변:


426

카운터를 사용할 수 있습니다.

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

24
나는이 또한 제대로 작동 여기에 이루어져야 downvoting 생각하지 여전히 사용하는 등 너무 쓰레기하지 않습니다 array_shiftarray_pop. 이것이 내가 그런 것을 구현해야했을 때 나왔던 해결책이지만, 지금 Rok Kralj의 대답을 고수 할 것 입니다.
shadyyx

15
카운터가 필요하면 FOREACH 대신 FOR 루프를 사용하는 것이 좋습니다.
rkawano

10
당신이 사용하는 경우 $i = 1, 당신은 걱정하지 않아도 $len - 1바로 사용 $len.
aksu

2
@Twan 포인트 # 3은 어떻습니까? 아니면 HTML과 관련이 있기 때문에이 질문과 관련이 있습니까? 이것은 분명히 PHP 질문입니다. 마크 업 의미론에 관해서는 "올바른 블라 블라는 항상 블라 블라보다 낫습니다."
Deji

1
@rkawano하지만 당신은 얻을 수 없다 라는 이름의 키를 사용하면 FOR 루프를 사용하는 경우
Fahmi

1015

루프 외부에서 카운터를 초기화하지 않아도되는 솔루션을 선호하는 경우 현재 반복 키를 배열의 마지막 / 첫 번째 키를 알려주는 함수와 비교하는 것이 좋습니다.

이것은 다가오는 PHP 7.3에서 다소 더 효율적이고 읽기 쉽습니다.

PHP 7.3 이상의 솔루션 :

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

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

모든 PHP 버전에 대한 솔루션 :

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

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

44
환상적인 답변! 많은 배열을 사용하는 것보다 훨씬 깨끗합니다.
Paul J

14
정답이므로 맨 위로 버블 링해야합니다. array_shift 및 array_pop을 사용하는 것보다 이러한 기능의 또 다른 장점은 나중에 필요할 때 배열이 그대로 유지된다는 것입니다. 지식을 공유하기 위해 +1합니다.
Awemo

13
코드를 깨끗하게 유지하려는 경우 이것이 가장 좋은 방법입니다. 나는 그것을 공언하려고했지만 지금은 그 배열 방법의 기능적 오버 헤드가 가치가 있다고 확신하지 않습니다. 우리가 마지막 요소에 대해서만 이야기 한다면 루프의 모든 반복에 대해 end()+ key()입니다. 둘 다라면 매번 호출되는 4 개의 메소드입니다. 허락하신다면, 사람들은 매우 가볍고 작업이 될 것이며, 아마 포인터 조회가 있지만 그 문서는 그 지정에 가야합니까 reset()end() 수정 배열의 내부 포인터 - 그래서 카운터보다 더 빨리입니까? 아마도 아닙니다.
pospi 2018 년

19
foreach 내에서 reset ($ array)을 발행해야한다고 생각하지 않습니다. 공식 문서 (www.php.net/foreach)에서 : "foreach는 내부 배열 포인터를 사용하여 루프 내에서 포인터를 변경하면 예기치 않은 동작이 발생할 수 있습니다." 그리고 리셋은 정확히 그렇게합니다 (www.php.net/reset) : "배열의 내부 포인터를 첫 번째 요소로 설정"
Gonçalo Queirós

11
@ GonçaloQueirós : 작동합니다. Foreach는 어레이 사본에서 작동합니다. 그러나 여전히 우려되는 reset()경우 foreach 전에 통화 를 이동 하고 결과를에 캐시하십시오 $first.
Rok Kralj

121

마지막 항목을 찾기 위해 매번이 코드가 작동한다는 것을 알았습니다.

foreach( $items as $item ) {
    if( !next( $items ) ) {
        echo 'Last Item';
    }
}

2
업 보트가 너무 적습니다. 이것을 사용하는 데 단점이 있습니까?
Kevin Kuyl


2
@Kevin Kuyl-위의 Pang에서 언급했듯이, 배열에 PHP가 false로 평가하는 항목이 포함 된 경우 (예 : 0, "", null)이 메소드는 예기치 않은 결과를 초래합니다. ===를 사용하도록 코드를 수정했습니다.
Eric Kigathi

4
이것은 대부분 매우 훌륭하지만 다른 사람들이 문제를 명확히하기 위해 배열과 함께 항상 실패 할 것이라고 지적합니다 [true,true,false,true]. 그러나 개인적으로 나는 boolean을 포함하지 않는 배열을 처리 할 때마다 이것을 사용할 것 false입니다.
billynoah

4
next()되어야 절대 foreach는 루프 내부에 이용되지. 내부 배열 포인터를 엉망으로 만듭니다. 자세한 내용은 설명서를 확인하십시오.
Drazzah

89

위의보다 단순화 된 버전이며 사용자 정의 색인을 사용하지 않는다고 가정합니다 ...

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

버전 2-필요하지 않으면 다른 것을 사용하여 싫어하기 때문에.

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

    if ($index == $len - 1) {
        // last
        // do something
        continue;
    }
}

8
이것은 객체에도 적용됩니다. 다른 솔루션은 어레이에서만 작동합니다.
Lamy

1
이것은 나에게 가장 좋은 대답이지만 압축해야하며 foreach 루프 외부의 길이를 선언하는 점은 없습니다 : if ($ index == count ($ array) -1) {...}
Andrew

2
@Andrew는 모든 반복에 대해 배열의 요소를 계속 계산합니다.
pcarvalho

1
@peteroak 그렇습니다. 실제로 기술적으로 성능을 떨어 뜨리고 계산 횟수 또는 루프 수에 따라 크게 달라질 수 있습니다. 내 의견을 무시하십시오 : D
Andrew

4
@peteroak @Andrew 배열의 총 요소 수는 내부적으로 속성으로 저장되므로을 수행해도 성능 저하가 발생하지 않습니다 if ($index == count($array) - 1). 여기를 참조 하십시오 .
GreeKatrina

36

배열에서 첫 번째 요소와 마지막 요소를 제거하고 별도로 처리 할 수 ​​있습니다.

이처럼 :

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

인라인 태그 대신 CSS의 모든 서식을 제거하면 코드가 향상되고로드 시간이 단축됩니다.

가능할 때마다 HTML을 PHP 논리와 혼합하는 것을 피할 수도 있습니다.

다음과 같이 분리하면 페이지를 훨씬 더 읽기 쉽고 유지 관리 할 수 ​​있습니다.

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

20

첫 번째를 찾으려는 시도는 다음과 같습니다.

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

3
코드 작동 방식 및 OP 문제 해결 방법에 대한 설명을 추가하려면 답변을 편집하십시오. 많은 SO 포스터는 초보자이며 게시 한 코드를 이해하지 못합니다.
나는

4
이 답변은 루프의 마지막 반복인지 확인하는 방법을 말하지 않습니다. 그러나 답변에 대한 올바른 시도이므로 답변이 아닌 것으로 표시되어서는 안됩니다. 마음에 들지 않으면 투표하지 말고 깃발을 쓰십시오.
ArtOfWarfare

첫 번째 반복에서 첫 번째 조건을 입력 한 다음 값을 false로 변경하면 첫 번째 반복으로 한 번만 입력됩니다.
Mohamed23gharbi 오전

20

간단하게 작동합니다!

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

최종 문제 를 해결해 주신 @billynoah에게 감사드립니다 .


3
베스트! 나는 단지 명확히 할 것이다 if ($key === $lastkey).
Krzysztof Przygoda

2
이러면 안되나요 if ($lastkey === $key)?
Kinetic

1
내가 얻을 :PHP Warning: key() expects parameter 1 to be array, integer given in php shell code on line 1
billynoah

1
@Sydwell-오류를 읽으십시오. key()아닌 정수를 받고 end()있습니다. end()" 마지막 요소의 값을 반환 "을 key()입력으로 배열을 기대하고있다.
billynoah


11

1 : 왜 간단한 for진술을 사용하지 않습니까? 실제 배열을 사용한다고 가정 Iterator하고 카운터 변수가 0인지 또는 전체 요소 수보다 하나 작은 지 쉽게 확인할 수 있습니다. 내 생각에 이것은 가장 깨끗하고 이해하기 쉬운 해결책입니다 ...

$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 : 중첩 구조를 사용하여 트리 구조를 저장하는 것을 고려해야 합니다. 또한 재귀 함수를 사용하여 모든 것을 향상시킬 수 있습니다.


당신이 사용하고자하는 경우 for에서 당신은 루프 수를 1n-1하고 걸릴 if몸 밖으로이야. 반복해서 확인하는 것이 중요하지 않습니다.
mpen

9

가장 좋은 답변 :

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

}

2
배열에 하나의 요소 만 있으면 실패합니다.
Memochipan

4
배열에 항상 하나 이상의 lement가 있는지 확인할 수있는 한 빠르고 쉽습니다 (Memochipan이 말했듯이). 따라서 그것은 나에게 안전한 솔루션이 아닙니다. '최고의 대답'은 없습니다.
Seika85

5
PHP 7.2.0부터는 each ()가 더 이상 사용되지 않습니다 . php.net/manual/en/function.each.php
Flow

8

@morg 의 가장 효율적인 답변foreach해시 맵 객체가 아닌 적절한 배열에서만 작동합니다. 이 대답은 첫 번째 요소와 마지막 요소 를 구체적으로 처리하고 중간 요소를 반복 함으로써 대부분의 이러한 대답 (허용 된 답변 포함)에서와 같이 루프의 모든 반복에 대한 조건 문의 오버 헤드를 피합니다 .

array_keys함수를 사용하면 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++;

나는 이것에 대해 벤치마킹을하지 않았지만 루프에 로직이 추가되지 않았습니다.

이런 종류의 기능기능화 하고 싶다면 여기 iterateList 함수 에서 스윙을했습니다 . 그러나 효율성에 관심이 있다면 요점 코드를 벤치마킹 할 수 있습니다. 모든 함수 호출로 인해 오버 헤드가 얼마나 많은지 잘 모르겠습니다.


6

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 밀리 초

따라서 검사 비용이 많이 든다는 것이 분명합니다. 물론 추가 변수 검사가 많을수록 악화됩니다.)


증분 정수 키가 있어야하는 경우에만 코드가 작동합니다. $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++;0: , 1: One, 2: ,
Seika85

해시 맵을 배열로 캐스트하는 것은 정의 할 수없는 동작입니다. "객체" array()는 만들어 {'one':"1 1 1",0:"",1:"One",2:"",3:"",4:"Four"}졌지만 빈 요소는 카운트로 무시됩니다. 정의 된 "사물"의 수를 세고 있습니다 !! 바운티 희생 수신! 이 답변은 현상금이 필요하지만 @Morg이면 가능합니다. 사라졌다, 그것은 무의미하다. 나는 아마 다시 사용하지 않을 사람에게 현상금을 줄 것입니다! 그가 돌아와서 답을 향상 시키면, 현상금을받을 자격이 있습니다!
mjz19910

@ mjz19910 메모와 같이 해시 맵과 배열은 서로 바꿔 사용할 수 없습니다. 그러나 array_keys함수 를 사용하여 해시의 속성을 얻을 수 있으며 이를 배열처럼 취급 할 수 있습니다 . 내 "향상된"답변을 참조하십시오 .
TheMadDeveloper 1

이것이 내가 쿼리에 사용하는 것입니다 :$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

키와 값을 사용하면 다음과 같이 작동합니다.

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

2
이렇게하면 값을 비교하고 배열에 두 개의 동일한 요소가 포함되어 있으면 작동하지 않습니다.
Krzysztof Przygoda

5

부울 변수를 사용하면이의 첫 등장을 검사 할 경우에도, 여전히 가장 신뢰할 수있다 $value (I 내 상황에서 많은 상황에서 더 유용하다고) 등과 같이 :

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

그런 다음 반복 할 값이 없으면 반환 할 !next( $array )마지막을 찾는 방법은 무엇 입니까?$valuetruenext()

그리고 나는 다음과 같이 카운터를 사용하려고하는 for대신 루프 를 사용하는 것을 선호합니다 foreach.

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

4

같은 문제가있을 때이 스레드를 발견했습니다. 첫 번째 요소 만 가져와야 내 마음에 올 때까지 코드를 다시 분석해야합니다.

$firstElement = true;

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

위의 코드는 훌륭하고 완전하지만 첫 번째 요소 만 필요한 경우이 코드를 사용해보십시오.


2

여전히 필요한지 확실하지 않습니다. 그러나 다음 솔루션은 반복자와 함께 작동해야하며 필요하지 않습니다 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;
        }
    }
}

0

익명 기능도 사용할 수 있습니다.

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

세 가지를 더 언급해야합니다.

  • 배열이 엄격하게 (숫자 적으로) 색인화되지 않은 경우 array_values먼저 배열을 파이프해야합니다 .
  • 수정이 필요한 경우 $element참조로 전달해야합니다 ( &$element).
  • 내부에 필요한 익명 함수 외부의 모든 변수는 필요한 경우 참조로 참조 $indexOfLastElement내부 use구조 옆에 변수를 나열해야 합니다.

0

카운터 및 배열 길이를 사용할 수 있습니다.

    $ array = 배열 ​​(1,2,3,4);

    $ i = 0;
    $ len = count ($ array);
    foreach ($ arm으로서 $ array) {
        if ($ i === 0) {
            // 먼저
        } 그렇지 않으면 ($ i === $ len-1) {
            // 마지막
        }
        //…
        $ i ++;
    }

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

0

사용 리셋 ($ 배열)끝 ($ 배열)

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

    }

데모 반복


-2

이 시도:

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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.