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 2013年

15
カウンターが必要な場合は、FOREACHではなくFORループを使用します。
rkawano 2014年

10
を使用する場合$i = 1、心配する必要はありません。$len - 1使用してください$len
aksu 2015

2
@Twanポイント3はどうですか?それともHTMLが関係するので、この質問にまったく関連していますか?これはPHPの質問です。マークアップのセマンティクスについては、「適切なblahblahは常にblahblahよりも優れています(これは私の意見ではなく、純粋な事実です)」よりもはるかに深い事実です。
Deji、2015

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つの利点は、後で必要になった場合に備えて、配列がそのまま残されることです。+1は、そのためだけに知識を共有するためのものです。
Awemo 2012

13
コードをクリーンに保ちたい場合は、これが間違いなく最良の方法です。私はそれを賛成しようとしていましたが、これらの配列メソッドの機能的なオーバーヘッドが価値があると確信していません。end()+ 最後の要素について話しているだけの場合、それはkey()ループのすべての反復で+ です。両方の場合、それは毎回呼び出される4つのメソッドです。確かに、これらは非常に軽量な操作であり、おそらく単なるポインタルックアップですが、ドキュメントはそれを指定して配列の内部ポインタreset()end() 変更します。カウンタよりも速いのでしょうか。おそらくない。
pospi

19
foreach内でreset($ array)を発行するべきではないと思います。公式ドキュメント(www.php.net/foreach)から:「foreachは、ループ内で変更する内部配列ポインターに依存しているため、予期しない動作を引き起こす可能性があります。」「その最初の要素を配列のセットの内部ポインタ」:そして、リセットは、正確にその(www.php.net/reset)を行います
ゴンサーロQueirós

11
@GonçaloQueirós:動作します。Foreachは配列のコピーに対して機能します。ただし、それでも問題がある場合は、reset()呼び出しをforeachの前に移動して、結果をにキャッシュしてください$first
Rok Kralj 2013年

121

最後の項目を見つけるために、私はこのコードが常に機能することを発見しました:

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

2
これには賛成票が少なすぎます。これを使用することには欠点がありますか?
Kevin Kuyl 2016


2
@Kevin Kuyl-上記のPangで述べたように、配列にPHPがfalseと評価するアイテム(つまり、0、 ""、null)が含まれている場合、このメソッドは予期しない結果になります。使用するコードを修正しました===
Eric Kigathi

4
これは主に非常に素晴らしいですが、問題を明確にするために他の人が指摘しているように、常にのような配列で失敗し[true,true,false,true]ます しかし、個人的には、booleanを含まない配列を扱うときはいつでもこれを使用しますfalse
ビリーノア2017年

4
next()必要がありますNEVER foreachループ内で使用しないこと。内部の配列ポインタを破壊します。詳細については、ドキュメントをご覧ください。
Drazzah

89

上記のより簡略化されたバージョンで、カスタムインデックスを使用していないと想定しています...

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

バージョン2-必要がない限り、elseを使うのが嫌いになったため。

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

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

8
これはオブジェクトに対しても機能します。他のソリューションはアレイに対してのみ機能します。
ラミー

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 2014年

明らかです。最初の反復で彼は最初の条件に入り、その値をfalseに変更します。このようにして、最初の反復に1回だけ入ります。
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)か?
キネティック2017年

1
私は得る:PHP Warning: key() expects parameter 1 to be array, integer given in php shell code on line 1
ビリーノア

1
@Sydwell-エラーを読んでください。 key()ではなく、整数を取得していend()ます。 end()" は最後の要素の値を返します "、そしてkey()入力として配列を期待します。
ビリーノア2018


11

1:単純なforステートメントを使用しないのはなぜですか?実際の配列ではなく実際の配列を使用しているとするとIterator、counter変数が0であるか、要素の総数よりも1少ないかを簡単に確認できます。私の意見では、これは最もクリーンでわかりやすいソリューションです...

$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からすることができますループ1にするn-1と取るif体からね。それらを繰り返しチェックするポイントはありません。
mpen 2016年

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
配列に要素が1つしかない場合、これは失敗します。
Memochipan 2014年

4
配列に常に複数の要素があることを確認できる限り、高速で簡単です(メモチップが言ったように)。だから私にとってはフェールセーフなソリューションではありません-「ベストアンサー」はありません。
Seika85 2014年

5
each()は、PHP 7.2.0以降廃止される予定です。php.net/manual/en/function.each.php
フロー

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クエリ生成スクリプト、または最初または最後の要素に対して異なるアクションを実行するものの場合、不要な変数チェックの使用を回避する方がはるかに高速(ほぼ2倍高速)です。

現在受け入れられているソリューションでは、ループと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の10万回の実行

時間: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"}が、空の要素はcountで無視され、定義された「もの」の数を数えています!! バウンティの犠牲がやって来る!この答えは賞金に値しますが、@ Morgなら。なくなった、それは無意味です。もう二度とSOを使わない人に報奨金をあげよう!彼が戻って答えを改善した場合、彼は賞金に値します!
mjz19910 2016年

@ mjz19910が注記しているように、ハッシュマップと配列は交換可能ではありません。ただし、配列のように扱うarray_keysことができる関数を使用して、ハッシュのプロパティを取得できます。私の「改善された」答えをください。
TheMadDeveloper

それは私がクエリに使用するものです:$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'";
ロブシャンマメドフ

5

キーと値を使用すると、これも機能します。

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

2
この方法では、値を比較していて、配列に2つの同じ要素が含まれている場合は機能しません。
Krzysztof Przygoda

5

ブール変数の使用は、次のように、最初の外観を確認したい場合でも、最も信頼性が高くなります$value (私の状況や多くの状況で、より便利であることがわかりました)

$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 )、ない場合に$value返さtrueれる最後のものを見つける方法についてnext()、反復する値が。

そして、次のようにカウンターを使用する場合は、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
    }
});

さらに3つの点に言及する必要があります。

  • 配列が厳密に(数値的に)インデックス付けされていない場合は、array_values最初に配列をパイプ処理する必要があります。
  • 変更する必要がある$element場合は、参照(&$element)で渡す必要があります。
  • 内部で必要な無名関数の外部からの変数はすべて$indexOfLastElementuse構造体内の隣にリストする必要があります。これも必要に応じて参照によって行います。

0

カウンタと配列の長さを使用できます。

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

    $ i = 0;
    $ len = count($ array);
    foreach($ array as $ item){
        if($ i === 0){
            // 最初
        } else if($ 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.