I have a for loop where I must skip the first element in a zero-based array.
Which of these shows my intentions more clearly?
for($i=1 ; $i < count(array) ; $i++){
array[$i];
}
or
for($i=0+1 ; $i < count(array) ; $i++){
array[$i];
}
I hate both.
Who said you could use magic numbers? If you're going to start at an offset of 1 how about telling us WHY you're starting at an offset of 1. Adding an equally magic zero explains nothing to me.
Is this the payload offset? Is this some pascal string you're converting to a null terminated c string? Please tell us what is going on.
Sorry, but I've wasted much of my career decoding pointless mysteries like this and my patience for them has worn thin. Is a variable with a decent name really to much to ask?
By decent name I mean a name that explains WHY we're skipping the first element. Not something that simply says THAT we're skipping the first element. The 1 told me that on it's own.
static final int LONELIEST_NUMBER = 1
in all my Java code. :-) That said, on further thought I'd like to undownvote your answer but can't unless you edit it. Silly SO rule?
Commented
Oct 7, 2016 at 19:46
Short answer: the first option is better.
The second option just adds noise. It is very unlikely that 0+1 helps the reader to understand that it could have been 0 but it is 1. Much more likely he will be puzzled a brief moment and distracted from what the loop is about. Especially in a language where all arrays start at 0.
As other mentioned, if you want to stress the fact that the loop starts from 1, not 0, just add a comment.
Don't tell us you're skipping the first item -- we can see that. What isn't obvious is why. So.. if it's not obvious from context, tell us why:
// array[0] is just a header
for($i=1 ; $i < count(array) ; $i++){
array[$i];
}
Or, if you're comment-averse, something like:
$lastHeaderIndex = 0;
for($i = $lastHeaderIndex + 1 ; $i < count(array) ; $i++){
array[$i];
}
Don't use comments and trickery to remind us how the language works.
Your example looks contrived. In real world code, the fact the loops needs to start at the second array element is most probably obvious from the following code lines. For example, if the real code looks like this
for($i=1 ; $i < count(array) ; $i++){
array[$i-1]=array[$i];
}
there would be no explanation or "0+1" construct needed to make clear why the loop starts at 1 instead of 0.
However, if the code inside the loop does not explain the reasons in such an obvious way (maybe array[0]
has a special meaning and must be dealt differently than the remaining elements), then add an explaining comment. But before you do this, think twice if you can avoid having array[0]
this special meaning, and reorganize the surrounding code, which would probably be the better alternative.
Never seen option #2, but I like it. Why? With option #1 I'd wonder if the programmer forgot that arrays start at 0. Option #2 makes it clearer that they are deliberately starting at 1.
That said, best in either case to add a comment why you are skipping element.
Or, if you can easily describe why you are starting at one, use a constant. For example, if looking at command line arguments, something like
define ('FIRST_REAL_ARGUMENT', 1);
for ($i=FIRST_REAL_ARGUMENT; ...)
Personally, I'd probably just use a comment instead, YMMV.
I doubt anyone would be confused by the first one. We've all had to do it. So much so that the second one is much more likely to confuse. "Why is there a 0+ there? Did they override the + operator somehow?"
A decent compiler will turn the second one into the first anyway, but it looks like you're using PHP, which is interpreted. So every time the interpreter hits that loop, it's going to have to actually add 0 and 1. Not a big deal, but why make the interpreter do the work?
Use a variable that explain the start point.
You need to "skip the first element in a zero-based array", so for example:
skipFirstElement = 1;
for($i=$skipFirstElement ; $i < count(array) ; $i++){
array[$i];
}
//We are skipping the first element because...
if ($i==0)
{ continue; }
If one is obsessive with all loops starting at zero you could use a continue statement. Add a comment to why you are skipping since normally one wouldn't.
if first then skip
with a comment saying why. Still without context none of the solutions are "best"
Commented
Oct 8, 2016 at 6:46
What I'd do is remove the first element before looping. Create a new array if you need to. Explain in a comment why you're doing it. And then just do a simple foreach.
$arrayCopy = $array; // in case you don't want to touch the original array
array_shift($arrayCopy); // removing first element because of X reason.
foreach($arrayCopy => $element) {
// do stuff
}
This way your intent is perfectly clear.
To clarify further you could wrap the code in a method with an appropriate name to make things clearer.
function doStuffToAllButTheFirst($array) { // this copies the original array, so there are no sideffects
array_shift($array);
foreach($array => $element) { // do stuff }
}
However all of this is still missing context. What do you want to do with the elements? Will you be returning the new array? Do you care about the original and the new array after you doStuff()
?
Anyway, there's no clear answer here, and deciding how to make the code readable depends greatly on the context.
$array[$i-1] = $array[$i]
or something similar, as per @DocBrown's answer?
Commented
Oct 7, 2016 at 22:59
1
(see Kevin Lee's comment), it doesn't make the code any clearer at all. The reader must understand array_shift, what it does, how it works. Maybe this line of code is a bug? Does it modifiy the array or return a new one? Does it insert an element or remove one? Does it change indices or not? I fail to see how using a one-based loop would not be a huge improvement in that function (and given its name, instantly understandable).
$i=2-1
is the superior way. :/foreach ($i in range(1, count))
(whatever that looks like in PHP). Or something likeforeach ($item in array.skip(1))
which is what a C# person would do.