tags:

views:

115

answers:

5

Hello, I am writing a foreach that does not start at the 0th index but instead starts at the first index in my array is there anyway to offset the loop's starting point?

+2  A: 

In a foreach you cant do that. There are only two ways to get what you want:

  1. Use a for loop and start at position 1
  2. use a foreach and use a something like if($key>0) around your actual code

A foreach does what its name is telling you. Doing something for every element :)

EDIT: OK, a very evil solution came just to my mind. Try the following:

foreach(array_reverse(array_pop(array_reverse($array))) as $key => $value){
    ...
}

That would reverse the array, pop out the last element and reverse it again. Than you'll have a element excluding the first one.

But I would recommend to use one of the other solutions. The best would be the first one.

And a variation: You can use array_slice() for that:

foreach(array_slice($array, 1, null, true) as $key => $value){
    ...
} 

But you should use all three parameters to keep the keys of the array for your foreach loop:

Kau-Boy
using array_slice it is possible to do this in a foreach loop, but that practice should be highly discouraged and punishable by having to read that sort of code.
Kris
That's why I pointed out that it's an EVIL method to do that. But I wouldn't use any of the solutoins personally. I would use a if statement or a for loop.
Kau-Boy
A: 

You can use the array_slice function:

$arr = array(); // your array
foreach(array_slice($arr, 1) as $foo){
   // do what ever you want here
}

Of course, you can use whatever offset value you want. In this case, 1 'skip' the first element of the array.

Cristian
Worth nothing that this will require making a copy of that chunk of the array. Could be a bad thing if the array is large.
Michael Mior
You are right... this will work better for short arrays. Thanks for your comment.
Cristian
+1  A: 

Seems like a for loop would be the better way to go here, but if you think you MUST use foreach you could shift the first element off the array and unshift it back on:

$a = array('foo','bar');
$temp = array_shift($a);
foreach ( $a as $k => $v ) {
  //do something
}
array_unshift($a, $temp);
Swish
array_shirt? ;)
webbiedave
Just noting that the `$k => $v` syntax is only for associative arrays. For indexed arrays, you just want `$a as $v`.
Michael Mior
@webbiedave: fixed
BoltClock
@Michael: the $k => $v will also work for indexed array and return the index number of the current value.
Kau-Boy
Oh...cool! :D lol
Michael Mior
+4  A: 

Keep it simple.

foreach ($arr as $k => $v) {
   if ($k < 1) continue;
   // your code here.
}
TRiG
I like that solution. Is continue available with every version of PHP?
Kau-Boy
http://ie2.php.net/manual/en/control-structures.continue.php doesn't mention when it became available, so I assume it's been there from the beginning.
TRiG
and, if the array is not indexed?
Cristian
By the sound of it, Nialls Chavez's array is indexed from `0` to some high number, and he wants to do something from index `1` onward. In that situation, something like what I've written above will do nicely. Or, even shorter, `if (!$k) continue;`, perhaps.
TRiG
Or, all PHP arrays are indexed. If they're not explicitly indexed, they're indexed from `0` on.
TRiG
+2  A: 

A Foreach will reset the array:

Note: When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.

Either use a for loop (only if this is not a dictionary)

$letters = range('a','z');
for($offset=1; $offset < count($letters); $offset++) {
    echo $letters[$offset];
}

or a while loop (can be any array)

$letters = range('a','z');
next($letters);
while($letter = each($letters)) {
    echo $letter['value'];
}

or - if you want to use foreach at any cost - wrap the array into Iterators like this:

$letters = new NoRewindIterator(new ArrayIterator(range('a','z')));
$letters->getInnerIterator()->seek(1); // seeks to zero-based offset, not key
foreach($letters as $letter) {
    echo $letter;
}

or - suggested by salathe below - with a LimitIterator

$letters = new LimitIterator(new ArrayIterator(range('a','z')), 1);
foreach($letters as $letter) {
    echo $letter;
}

which lets you specify start offset and count through the constructor.

All of the above will output the letters b to z instead of a to z

Gordon
+1 for an OOP solution :)
Kau-Boy
Why the `NoRewindIterator`? A `LimitIterator` be more (resuable/)useful here.
salathe
@salathe to prevent `foreach` to reset the `seek()` position
Gordon
@Gordon, which wouldn't be an issue with a `LimitIterator` ;)
salathe
@salathe ok. added and i agree it's more befitting to the UseCase. Thanks!
Gordon