breaking a for loop with length decrement - javascript

I found this code to convert an excel column name into a column number but having a hard time understanding the break condition for the loop
//function convert excel sheet column to number
toColumnNumber = (colName) => {
let result = 0;
for (let i = colName.length, j = 0; i--; j++) {
result += Math.pow(26, i) * (colName.charCodeAt(j) - 64);
}
return result;
};
console.log(toColumnNumber("AB"));
it uses i-- as a break condition and i can't understand how it can be used to break the loop. or is it just that is how javascript works when we use i-- as a break condition and it reaches 0 it breaks the loop?

As we keep decrementing the value of i, eventually it reaches 0 and that would be falsy and would stop the loop.
This is just a fancy way of doing:
for (let i = colName.length, j = 0; i > 0; j++, i--) {
result += Math.pow(26, i) * (colName.charCodeAt(j) - 64);
}

Related

Why is the loop not iterating for compounding investment calculation in JS

I'm writing a function to calculate investment return over period of years. However, the function seems to be only able to calculate for one year. If the totalyears is more than 1, the loop as shown below is not iterating and it returns wrong value.
const calc = (initial, monthlyContribution, totalyears, annualisedReturn) => {
let sum = initial;
for (i = 0; i < totalyears; i++) { // ISSUE: THIS NOT LOOPING WHEN totalyears > 1
let balance = sum;
let totalBalance = 0;
for (i = 0; i < 12; i++) {
totalBalance = totalBalance + balance;
balance = balance + monthlyContribution;
}
sum = balance + (totalBalance / 12) * (annualisedReturn / 100);
}
return sum;
};
console.log(calc(0, 100, 2, 10)); // This return 1255 which is wrong
You're using the same global variable for both loops. i will have the value 12 when leaving the inner loop, thus the condition of the outer loop will be false
You are using the same variable "i" in the inner loop and you are not declaring it again.
So when you start the loop with i=0, your inner loop will first make i=0 again, then it will increase until i=12, and then the same variable is used in the first loop, so it will go from 0 to 12, skipping iterations. Use "i, j,k" for nested loops.
Something like this:
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
}
}

javascript for loop to achieve particular output?

How would I get a standard for loop to output in pairs or other groups (like three's of four's) with the output shifting up one after the last digit of the group?
for(var i = 0: i < 8; i++){
console.log(i)
}
so instead of the output being; 0,1,2,3,4,5,6,7
In pairs it would be; 0,1,1,2,2,3,3,4
or if it went up in groups of four; 0,1,2,3,1,2,3,4
I did try doing something like this, but instead of going up in two's every time I need the loop to output the first 2 digits move up one then output the next two ect...
for(var i = 0: i < 8; i+= 2){
console.log(i)
}
Hope that makes sense
For each case you would need to come up with the right formula based on i:
so instead of the output being; 0,1,2,3,4,5,6,7 In pairs it would be; 0,1,1,2,2,3,3,4
for (let i = 1; i < 9; i++) {
console.log(i >> 1); // this bit shift is integer division by 2
}
or if it went up in groups of four; 0,1,2,3,1,2,3,4
for (let i = 0; i < 8; i++) {
// Perform division by 4 and add remainder to that integer quotient
console.log((i >> 2) + (i % 4));
}
You could work with a variable inside the loop to determine the index. This way you can specify how many times you want the loop to run:
for(let index = 0; index < 8; index++) {
const currentIndex = index - (index >> 1);
console.log(currentIndex);
}
It also makes it easy to implement it as immutable:
const array = new Array(8).fill(0).map((entry, index) => index - (index >> 1));
console.log(array);
I think a function like below where we specify the total n and the chunksize after which you want to increase a single step might work for us :-
function getByChunkSteps(n,chunkSize){
let step = -1;
let output = [];
for(let index = 0;index < n;index++){
if(index%chunkSize===0){
step+=1;
}
output.push((index%chunkSize)+step);
}
return output;
}
console.log(getByChunkSteps(10,2));
console.log(getByChunkSteps(8,4));
console.log(getByChunkSteps(9,3));

Javascript print square using for loop and conditional statement only

Just started my uni course, struggling a little with javascript. I have been asked to display a square using any character, however, the solution must combine for loops and if statements.
This is what I have so far and I feel pretty close but I just can't get the second line to display. I know this can be done via two for loops, (one for iteration of the variable and another for spaces). But this is not how I have been asked to solve this problem.
Here is my code:
var size = 3;
let i;
for(i = 0; i < size; i++) {
print ("*");
if (size === i){
println ("");
}
}
For context, this is all taking place int he professors homemade learning environment.
You could use nested for loops and take a line break after each filled line.
function print(s) { document.getElementById('out').innerHTML += s; }
function println(s) { document.getElementById('out').innerHTML += s + '\n'; }
var size = 5,
i, j;
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
print("*");
}
println("");
}
<pre id="out"></pre>
Single loop with a check if i is unequal to zero and if the remainder is zero, then add a line break.
Using:
=== identity/strict equality operator checks the type and the value, for example if both are numbers and if the value is the same,
!== non-identity/strict inequality operator it is like above, but it checks the oposite of it,
% remainder operator, which returns a rest of a number which division returns an integer number.
&& logical AND operator, which check both sides and returns the last value if both a truthy (like any array, object, number not zero, a not empty string, true), or the first, if it is falsy (like undefined, null, 0, '' (empty string), false, the oposite of truthy).
function print(s) { document.getElementById('out').innerHTML += s; }
function println(s) { document.getElementById('out').innerHTML += s + '\n'; }
var size = 5,
i;
for (i = 0; i < size * size; i++) {
if (i !== 0 && i % size === 0) {
println("");
}
print("*");
}
<pre id="out"></pre>
Well the for loop is only iterating 3 times, printing the first line. If you want a square you'll have to print 9 stars total, right? So i'm assuming, is this is the approach you'd go for, you would need to iterate not until size, but until size * size.
I'm using console.log to 'print' the square:
var dimension = 10;
var edge = '*';
var inside = ' ';
var printLine;
for (var i = 1; i <= dimension; i++) {
if (i === 1 || i === dimension) {
printline = Array(dimension + 1).join(edge);
} else {
printline = edge + Array(dimension - 1).join(inside) + edge;
}
console.log(printline);
}
Note that in the following example, an array of length 11 gets you only 10 "a"s, since Array.join puts the argument between the array elements:
Array(11).join('a'); // create string with 10 as "aaaaaaaaaa"
You wanna make a square of * where the size is the number of * on its sides?
Let's split a task into 3 parts:
where you print top side like *****
where you print middle (left and right sides) like * *
where you print bottom (same as top)
Now let's code that, I kept the code as simple as possible, this can be done in fewer lines but I think this will be easier to understand for beginners:
var size = 5;
var i = 0;
// top
for (i = 0; i < size; i++)
console.log("*");
//middle
for (var j = 0; j < size - 2; j++){
console.log("\n"); // go to next row
// middle (2 on sides with size-2 in between)
console.log("*");
for (i = 0; i < size-2; i++)
console.log(" ");
console.log("*\n"); // goes to new row as well
}
// same as top
for (i = 0; i < size; i++)
console.log("*");
Full square is even simpler:
var size = 5;
var i = 0;
for (var i = 0; i < size; i++){ // iterates rows
for (var j = 0; j < size; j++) // iterates * in row
console.log("*");
console.log("\n") // moves to new row
}
In order to print a row, you print same sign X times. Well, to print X rows we can use just that 1 more time (only this time we are iterating over a different variable (j is * in a row, i is a number of rows).
After a row is made we go to go to next row with \n.
As for
it must contain if statement
Put this at the end:
if (youCanHandleTheTruth) console.log("It's a terrible practice to tell students their solution MUST CONTAIN CODEWORDS. If you need them to showcase something, write appropriate task that will require them to do so.");

When does this for loop escape?

To check my understanding, do we have that the following for loop never escapes only if row.length < n (otherwise, the loop can escape)?
function someFunction (matrix,n) {
for (var i = 0; i < n; i += 1) {
var row = matrix[i];
for (var i = 0; i < row.length; i += 1) {
if (row[i] < 0) {
alert("Something's wrong");
}
}
}
}
Do not use the same incrementing variable in nested for loops!
function someFunction(matrix,n) {
for (var i = 0; i < n; i += 1) {
var row = matrix[i];
for (var i = 0; i < row.length; i += 1) { //VERY BAD!!!
if (row[i] < 0) {
alert("Something's wrong");
}
}
}
}
When the inner loop completes the first loop, i will equal row.length. This will also complete the outer loop, which increments i again by 1. Thus, when the outer loop goes to begin its second iteration, you will have i=row.length+1. Do this instead:
function someFunction(matrix,n) {
for (var i = 0; i < n; i += 1) {
var row = matrix[i];
for (var j = 0; j < row.length; j += 1) { //using j instead of i
if (row[j] < 0) {
alert("Something's wrong");
}
}
}
}
It's bad practice to use the same loop counter i for the inner and outer loops. That's just confusing and leads to unpredictable behaviour.
But since you have done so and you want to know what will happen:
When the inner loop finishes for the first time, i will have the value of row.length from the first row in your matrix. i will then be incremented by the outer loop. If this new value of i is >= your n variable then the outer loop will end immediately. Otherwise the outerloop will continue with the new value of i and execute this line:
var row = matrix[i];
At that point if i is greater than or equal to matrix.length the row variable will be undefined, so then when you get to the inner loop and try to test row.length you are testing undefined.length which will give you an error and stop execution.
But if i is less than or equal to matrix.length then the inner loop would "work" in the sense of running again with the new value of row and with i set back to 0 for its first iteration.
If the previous row's length happened to be same as its index minus 1 then the same row would be processed over and over forever.
So essentially every iteration of the outer loop is selecting a more or less random (and possibly undefined) row to continue with based on whatever the length of the previous row was.

Javascript Averages

I am trying to learn Javascript. I've built the following code to find the average from an array of numbers. It works except the last returned value is always NaN. I cannot figure out why. If I move this piece outside of the block it seems to forget altogether what the variable sum is supposed to be equal to. Is there some kind of global-variable type equivalent I'm supposed to be using for JS?
var average = function(myarray) {
sum = 0;
for (counter = 0; counter <= myarray.length; counter++) {
sum = sum + myarray[counter];
average = sum / myarray.length;
console.log(average);
};
}
average([1, 2, 3])
Change
counter <= myarray.length
to
counter < myarray.length
because indexes start at 0.
Full example:
var average = function(myarray) {
var sum = 0;
for (var counter = 0; counter < myarray.length; counter++) {
sum += myarray[counter];
}
return sum / myarray.length;
}
console.log(average([1,2,3]));
JSBin Demo: http://jsbin.com/siyugi/1/edit
myarray[myarray.length] is undefined, which intoxicates your computation with NaN(Not A Number).
Just change it to
for(counter = 0; counter < myarray.length; counter ++) {
// ...
}
Since you are just learning you should know it is good practice to not use .length in a for loop like that. It causes the code to have to check the length of your array on each loop. And remember that .length is returning the number of elements in the array; but array index starts at 0.
for(var counter = 0, length = myarray.length; counter < length; counter++){
}
Would be the proper way to do it.
Don't use variables without declaring them with var keyword, otherwise they will become global properties.
The JavaScript Arrays are zero index based arrays. So, if the size of the array is 3, then the first element will be accessed with 0 and the last with 2. JavaScript is very forgiving, so when you access an element at an invalid index in the array, it will simply return undefined.
In the iteration, you are replacing the current function object with the average value. So, subsequent calls to average will fail, since average is not a function object any more.
It is a good practice to have a function return the computed value, instead of printing the value, so that it will not violate the Single Responsibility Principle.
In your case,
for (counter = 0; counter <= myarray.length; counter++) {
The counter runs till the last index of the array + 1. Since it returns undefined in the last iteration, JavaScript returns NaN in the arithmetic operation.
console.log(1 + undefined);
# NaN
So, you need to change the code, like this
function Average(myarray) {
var sum = 0, counter;
for (counter = 0; counter < myarray.length; counter++) {
sum = sum + myarray[counter];
}
return sum / myarray.length;
}
If you are interested, you can compute the sum with Array.prototype.forEach, like this
function Average(myarray) {
var sum = 0;
myarray.forEach(function(currentNumber) {
sum += currentNumber;
});
return sum / myarray.length;
}
Even better, you can calculate the sum with Array.prototype.reduce, like this
function Average(myarray) {
return myarray.reduce(function(sum, currentNumber) {
return sum + currentNumber;
}, 0) / myarray.length;
}
You can calculate the average of an array of numbers as follows:
var avg = c => c.reduce((a,b) => a +b) / c.length;
avg([1,2,3])

Categories

Resources