snapsvg

2011-11-24

Testing for the end of a for(each) loop

One sign of a good templating language is that you can test for the last iteration of a loop without having to count the iterations. PHP is no exception! Assuming you're quite happy with hacky syntax (you have to be if you're using PHP) then you can do this:

foreach ($array as $item) {
  if (each($array) === false) {
    # last iteration
  }
}

You iterate over the original array using each, but ignore the output if it's not boolean false. foreach derps around on the copy of the array, and when the original array finishes being iterated, each returns false! So you basically iterate over the array while you iterate over the array.



In Template::Toolkit you can also test for the last iteration of a loop with loop.last, which is why that is also a good templating language.

In conclusion, PHP is a templating language.

Oh right, leave a comment with your own one for whatever bozo templating language you like :)

4 comments:

  1. Smarty also has it buildin through a special variable:
    {if $smarty.foreach.foreachname.last}
    {* do your thing here *}
    {/if}
    Of course "foreachname" if the name of your foreach loop.

    ReplyDelete
  2. Your post sparked a question in my head: http://stackoverflow.com/questions/8263293/why-does-phps-foreach-advance-the-pointer-of-its-array-only-once. It sees that this only works because foreach advances $array's internal pointer ahead before the loop begins -- otherwise iterating with each($array) wouldn't ever make it to the the last element inside the loop!

    ReplyDelete
  3. Maybe I'm not understanding correctly, but it looks like you went from O(n) to iterate over the array to O(n^2) by iterating over the entire array for each iteration of the foreach loop.

    ReplyDelete
    Replies
    1. No, because each() simply advances the internal pointer of the array by 1 on each iteration - this doesn't involve iterating over the rest of the array to do so. You are adding more work, but no more work than you'd have to add in order to keep a counter and increment that instead - and this way uses fewer lines.

      Delete