What does while (i --> 0) mean? - javascript

I apologize if this a stupid question, but I cannot find the answer anywhere.
How does the following code work? (I realize that it loops over the elements of els)
var i = els.length;
while (i --> 0) {
var el = els[i];
// ...do stuff...
}
I have no idea what --> means. There is no documentation for it. Can someone enlighten me?

It should be read as
i-- > 0
So, what really happens is,
value of i will be checked if it greater than 0, if it is true then control will enter the while block, if it is false while block will be skipped.
Either way, the value of i will be decremented, immediately after the condition is checked.
Its always better to use for loop, when we run a loop with a counter, like this
for (var i = els.length - 1; i >= 0; i -= 1) {
...
}
Please read more about whether ++, -- is okay or not.

It's just weird spacing, should be
while((i--) > 0)
it's just post-decrementing and checking the condition.
There was this humorous answer at the C++ question, but I think it got deleted
while (x --\
\
\
\
> 0) //i goes down to zero!
Or something like that, anyway
So if you had something like
var i=3;
while(i-->0){
console.log(i);
}
it would return
2
1
0

The code should actually be:
while (i-- > 0) {
where the loop will run if the value after the variable i has been decremented is greater than zero.

while (i--> 0)
{
// ...do stuff
}
is same as
while (i>0)
{
i--;
// ...do stuff
}
IMHO we should write simple code rather than clever code because it's not understandable by everyone.

It's just weird spacing. It's same as
while (i-- > 0) {

Related

How can I optimize a for-loop over a list of specific conditions?

I've got a for-loop in JavaScript, iterating over the variable i. In each iteration step, a list of if-conditions is checked. For each i, only one of these conditions can be true (or none of them) and every condition is true for exactly one i. A very simple example would be:
for (i = 1; i <= 10; i++)
{
if (i === 3) {some code ...}
if (i === 7) {some other code ...}
}
So obviously for 4 <= i <= 10 the condition i === 3 will always fail. Is there a way to achieve that if a condition is true for some i, this condition will not be checked any more for the other i's? Can this condition be deleted in some way? This would make the loop much faster.
(Of course the example of above does not make much sense and the real use case is much more complicated.)
Thank you in advance for your help!
Switch is better for what you're trying to achieve
for (i = 1; i <= 10; i++)
{
switch(i){
case 1:
some code..;
break; //once this is called, the statement will stop
case 3:
some other code..;
break;
}
}
You can use else if statements to skip all of the other conditions once one is found.
for (i = 1; i <= 10; i++) {
if (i === 3) {some code ...}
else if (i === 7) {some other code ...}
}
In this case, if i is 3, the other conditions will be skipped.

Having trouble with a for loop not iterating enough

So I have a problem with this FOR loop that I just can't quite figure out. In this case, I know this needs to iterate as least twice. The array, at a minimum, looks something like this...
dTrackerArray = {sParentValue, 1234, sParentValue, 5678}
But for some reason this for loop is only removing one instance instead of all of them.
var check = $.inArray(sParentValue, dTrackerArray);
if (check != -1) {
for(var i = dTrackerArray.length; i > 0; i--) {
if( dTrackerArray[i] === sParentValue ) {
dTrackerArray.splice(i,1);
dTrackerArray.splice(i-1,1);
}
}}
I really appreciate any help I can get here! Thanks!
EDIT: The 2nd splice is to remove the 1234 "associated" with the sParentValue. It seems to work ok.
The problem is in for loop. you start from: var i = dTrackerArray.length and take dTrackerArray[i] this element does not exist. More over you forgot to interate with 0 index element. So you have to change your for loop to:
for(var i = dTrackerArray.length-1; i >= 0; i--)
Easy to miss but you need i >= 0.
EDIT:
Although I think your main issue is that you're modifying an array while your looping. Obviously with my fix you'll get an out of bounds error on the second splice.
var check = $.inArray(sParentValue, dTrackerArray);
if (check != -1) {
for(var i = dTrackerArray.length; i >= 0; i--) {
if( dTrackerArray[i] === sParentValue ) {
dTrackerArray.splice(i,1);
dTrackerArray.splice(i-1,1); //when i == 0 then exception
}
}}
Since you know the format of the array you can do this with a while loop:
var check = $.inArray(sParentValue, dTrackerArray);
while(check > -1)
{
dTrackerArray.splice(check,1);
check = $.inArray(sParentValue, dTrackerArray);
}
You've already stepped through this with a debugger? That's probably all you'd need to do to understand what's happening here. I'd put this in a comment, but I don't have those privileges yet.

jQuery drying up function

As you can see below, I clearly repeat myself over. I understand that this is bad practice.
So, how can the 4 duplicate lines of code within the if and else statement be refactored into one?
Some guidance toward better practice would be greatly appreciated. Also, any DRY references / tutorials that you found helpful in learning this technique.
$('.inner_wrap .details').click(function() {
var index = $('.inner_wrap .details').index(this);
$('.details').removeClass('here');
$(this).addClass('here');
$('.view').removeClass('active');
$(this).find('.view').addClass('active');
console.log(index);
if(index > 2){
index -= 3;
**// This and its corresponding else statement is the topic of the question**
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');
} else {
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');
}
return false;
});
Note that the code is repeated in both if and else, meaning, it's always executed. Just take it out of the statement:
if (index > 2) {
index -= 3;
}
var elt = $(this).closest('.outer_wrapper').prev('.outer_wrapper');
elt.find('.tabSlide').removeClass('tabShow');
elt.find('.tabSlide:eq(' + index + ')').addClass('tabShow');
Next, note that the jQuery object is just an array. You can simplify your code thus:
if (index > 2) {
index -= 3;
}
var elt = $(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide');
$(elt.removeClass('tabShow')[index]).addClass('tabShow');
Finally, we can eliminate the aux variable, used just to demonstrate how you call the same object:
if (index > 2) {
index -= 3;
}
$($(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow')[index]).addClass('tabShow');
Please, break this into more than one line of code :D
[EDIT]
OK, and just for fun, here's an even more extreme astronaut-type code, getting rid of the remaining if:
$($(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow')[(index <= 2 ? index : index - 3)]).addClass('tabShow');
BUT! It's awfully unreadable and IMO, you should stick with just the first step. Until it becomes a performance issue, don't overdo it. Applying the DRY rule at the cost of readability/maintainability or just sticking everything into a single line of code makes as much sense as reading & writing minified code. Ie, don't do it :).
[EDIT 2]
#StuartNelson reminded me of the existence of the $.eq() function, which would bring the final code to this (broken into several lines):
$(this).closest('.outer_wrapper')
.prev('.outer_wrapper')
.find('.tabSlide')
.removeClass('tabShow')
.eq(index <= 2 ? index : index - 3)
.addClass('tabShow');
You can modify the index only using the if statement and you could keep a variable for the jQuery element used:
$('.inner_wrap .details').click(function() {
var index = $('.inner_wrap .details').index(this);
$('.details').removeClass('here');
$(this).addClass('here');
$('.view').removeClass('active');
$(this).find('.view').addClass('active');
console.log(index);
if(index > 2){
index -= 3;
}
var element = $(this).closest('.outer_wrapper').prev('.outer_wrapper');
element.find('.tabSlide').removeClass('tabShow');
element.find('.tabSlide:eq(' + index + ')').addClass('tabShow');
return false;
});
if(index > 2){ index -= 3; }
**// This and its corresponding else statement is the topic of the question**
$(this).closest('.outer_wrapper').prev('.outer_wrapper')
.find('.tabSlide').removeClass('tabShow')
.eq(index).addClass('tabShow')
Ditch the else, since you're executing that code regardless you don't need to include it in the statement. You can just keep working on the chain, also, since you're first targeting all elements with class tabSlide and then targeting just a specific instance of that class based on its index.
Those two lines are executed last in both the if and else clause, so they can be pulled out of both and put after the entire if/else statement:
if(index > 2){
index -= 3;
}
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');
This rule is always true. If they were the first two lines in both your if and else clause you would pull them out and put them before your if statement instead.
Since all you really care about is setting the index, that is the only thing you need in the if staement, the rest can go out:
if(index > 2){
index -= 3;
}
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide').removeClass('tabShow');
$(this).closest('.outer_wrapper').prev('.outer_wrapper').find('.tabSlide:eq(' + index + ')').addClass('tabShow');

Prevent javascript from going out of an array

Is there any way I can prevent javascript from dropping an error if I try to go into a non existing array index?
Example: array[-1] would return error and eventually break all my code. How can I let it just return 'undefined' and let my script go on? I can implement an if statement before checking the array (so that if the index is minor than zero or major than the array size it would skip it) but this would be very tedious!
this is my code:
if (grid[j-1][i])
n++;
if (grid[j+1][i])
n++;
if (grid[j][i+1])
n++;
if (grid[j][i-1])
n++;
if (grid[j-1][i-1])
n++;
if (grid[j+1][i+1])
n++;
if (grid[j-1][i+1])
n++;
if (grid[j+1][i-1])
n++;
It is inside of two loops which both sees J and I starting from zero. I don't want to change them and neither writing another if statement (as you can see, there are already too much of them!). Is there any solution?
Thanks!
If you know the measures of your grid, you can put "sentinel cells" around it.
If you add a -1st index to an array x, it does not count to x.length. Putting an additional last element into the list would increment x.length.
I daresay using sentinel cells combined with the arithmetic counting algorithms mentioned by d_inevitable would be the fastest solution, since it would not involve branches. You even can omit the !! because true will evaluate to 1 and false to 0 in an equalization.
Update:
Do not use index -1. Its an awful lot slower that normal array indexes. See http://jsperf.com/index-1.
You could use ||, which muffles errors, e.g.:
(grid[j-1] || [])[i] || false
(I haven't tested this, but it should work)
Edit: updated based on am not i am's suggestion
A less tedious way while still using ifs would be checking the first index if it's defined:
if (typeof grid[j-1] != "undefined" && grid[j-1][i])
You could create a function to do the checks:
function getArrayValue(arr,key) {
if( key < 0 || key >= arr.length) return null;
return arr[key];
}
But really you should be avoiding out-of-bounds keys anyway.
I would do this:
for(m = Math.max(j-1,0) ; m <= Math.min(j+1,grid.length-1) ; m++)
for (p = Math.max(i-1,0) ; p <= Math.min(i+1, grid[m].length-1) ; p++)
n += !(m == j && p == i) && !!grid[m][p];
How about this for your solution?
for (dj = -1; dj <= 1; ++dj) {
for (di = -1; di <= 1; ++di) {
if ((dj || di) && grid[j+dj] && grid[j+dj][i+di]) {
n++;
}
}
}
If you refactor all those ifs into a single loop like the above, then having to do the extra conditional is not so bad.

Javascript If Statement not Evaluating True

I am attempting to catch the last case in a forEach loop, but all cases seem to evaluate to false instead of the last one being true. My code:
for(var i in networks){
if (i == (networks.length - 1)){
//do stuff
}
}
What is going wrong?
Try this:
for(var i = 0, j = networks.length; i < j; i++){
if (i == (j - 1)){
//do stuff
}
}
I personally despise the for...in loop in JavaScript because it brings into the picture a whole bunch of unwanted properties, it's unreliable - needs a ton of sanity checks to make sure the current property is not of an unwanted type or undefined. I can go on and on about this. I suggest that the only time that you ever think of using it is when you are iterating over objects and you need key values.
If networks is an array of numbers in order from 0 to n, that should work. ;) If it's not, you might want to consider a standard for loop:
for(var i = 0; i < networks.length; i++) {
var network = networks[i]; // in case you need this.
if (i == (networks.length - 1)){
//do stuff
}
}

Categories

Resources