I am working my way through the javascript course on freecodecamp and im confused with the lesson on recursive functions.
I am having difficulty understanding the following code:
function sum(arr, n) {
if(n<=0) {
return 0;
} else {
return sum(arr, n-1) + arr[n-1];
}
}
sum([10,20,30,40], 3);
The specific part im struggling with is this:
arr[n-1];
would the return line not be returning sum([10,20,30,40], 3-1) + arr[3-1] resulting in 30+30 = 60?
Any help with this would be greatly appreciated. Or even pointing me in the right direction to look into this further.
Thanks
Let's write the original code in a more intuitive way by putting arr[n-1] first. This way we can keep expanding each call to sum() to the right.
But first let's note down what sum(arr, n) call will return for each n
if n > 0 => arr[n-1] + sum(arr, n-1)
if n == 0 => 0
n == 3 => arr[2] + sum(arr, 2)
n == 2 => arr[1] + sum(arr, 1)
n == 1 => arr[0] + sum(arr, 0)
n == 0 => 0
Now we expand our steps:
sum(arr, 3)
== arr[2] + sum(arr, 2) // expand sum(arr,2) where n = 2
== arr[2] + arr[1] + sum(arr, 1) // expand sum(arr,1)
== arr[2] + arr[1] + arr[0] + sum(arr,0) // expand sum(arr,0)
== arr[2] + arr[1] + arr[0] + 0
== 30 + 20 + 10 + 0
Test with
function sum(arr, n) {
console.log(`calling sum(arr, ${n})`);
if(n<=0) {
console.log(`returning 0`);
return 0;
} else {
console.log(`calculating [sum(arr, ${n-1}) + ${arr[n-1]}]`);
let s = sum(arr, n-1);;
console.log(`returning [sum(arr, ${n-1}) + ${arr[n-1]}] = [${s} + ${arr[n-1]}]`);
return s + arr[n-1];
}
}
sum([10,20,30,40], 3);
The output will be:
calling sum(arr, 3)
calculating [sum(arr, 2) + 30]
calling sum(arr, 2)
calculating [sum(arr, 1) + 20]
calling sum(arr, 1)
calculating [sum(arr, 0) + 10]
calling sum(arr, 0)
returning 0
returning [sum(arr, 0) + 10] = [0 + 10]
returning [sum(arr, 1) + 20] = [10 + 20]
returning [sum(arr, 2) + 30] = [30 + 30]
Two other classic examples of simple recursive functions are factorial and fibonacci, because those two formulas itself are recursive. Multiplication could also be computed recursively, if you think as a * b being a + (a + ...) where a is added b times.
If you're trying to code those functions, there's a hint to code this last example:
5 * 10 is equal to 5 + 5 * 9, which is equal to 5 + 5 + 5 * 8 and so on.
sum([10,20,30,40], 3-1) Will call sum function again, think about it.
Recursive functions usually operate with a value that is immediately accesible and another value that they obtain by calling themselves until a base case is reached.
In this example, that accesible parameter is one of the numbers of an array and the operation is just a simple addition. The base case will be reached when the function's parameters satisfy the if condition.
Think of the different iterations that happen here to understand how the final result is gotten:
First iteration, sum([10,20,30,40], 3)
The if condition is not fulfilled because 3 (n) is greater than 0, so the else branch's code is executed.
We have sum([10,20,30,40], 2) + arr[2]. We don't know the result of the recursive call yet but we have the value of the number located in the third position of the array, that is 30 (arrays are usually considered to start from 0).
Second iteration, sum([10,20,30,40], 2)
Again, this is not the base case yet (if branch), so we have:
sum([10,20,30,40], 2-1) + arr[2-1] ->
sum([10,20,30,40], 1) + arr[1] ->
sum([10,20,30,40], 1) + 20
Third iteration, sum([10,20,30,40], 1)
At this point, we have 30 and 20 as "partial results". These numbers and the results of the remaining iterations will all be added up, because that's what the code in the else branch does, an addition.
sum([10,20,30,40], 1-1) + arr[1-1] ->
sum([10,20,30,40], 0) + arr[0] ->
sum([10,20,30,40], 0) + 10
Another partial result has been added: 10.
Forth and final iteration, sum([10,20,30,40], 0)
The base case is finally reached, the if branch's code is executed and the recursion stops right here because there isn't another call to the recursive function in this code. The result of sum([10,20,30,40], 0) is 0 because the code returns 0.
Now that we have reached the end of the recursion, we can retrace our steps.
• The result of the third iteration is sum([10,20,30,40], 0) + 10. We know this is 0 + 10 now, so 10.
• The result of the second iteration is sum([10,20,30,40], 1) + 20 = 10 + 20 = 30.
• And the result of the first call and the original call to the function is sum([10,20,30,40], 2) + 30 = 30 + 30 = 60.
Recursive functions are really tricky at first but once you understand this logic of partial results that are "accumulated" until the moment the base case is reached, they get easier. Just take your time.
I have an example:
let x = 4
console.log(x++ + ++x + x--)
it's returns 16 but I don't understand how.
If we will look in MDN there is an operators precedence table.
So there is a precedence like this:
Postfix increment
Postfix decrement
Prefix increment
Addition
With this logic it should return 14
x++ = 4 - (5) -> remembers for next call
x-- = 5 - (4) -> remembers for next call
++x = 5
+
4 + 5 + 5 = 14
Can some one explain, how operators parser algorithm works with unary and binary operators?
Once operator precedence is applied, the grouping looks like:
((x++) + (++x)) + (x--)
The interpreter will evaluate the two +s left-to-right, and resolve the inner expressions as it comes across them. The increments/decrements don't run immediately and before the +s - they only run once the interpreter has determined that their expression needs to be evaluated. This is what happens, in order:
x is 4
((x++) + (++x)) + (x--)
evaluate postfix increment: insert 4, x increases to 5
(4 + (++x)) + (x--)
evaluate prefix increment: x increases to 6, insert 6
(4 + 6) + (x--)
simplify:
10 + (x--)
evaluate postfix decrement: insert 6, x decreases to 5
10 + 6
Resulting in a final value of 16.
The order is completely consistent. You are evaluating left-to-right and apply the precedence. I'll break it down in steps:
1. Post-increment x++
//x = 4
x++ + ++x + x--
^^^
|
--> expression = 4
--> x = 5
First off we evaluate x++. Postfix increment has higher precedence than the addition, so we have to solve it first. This expression produces 4 (value of x at the time) however, the value of x is also incremented for future reads.
2. Pre-increment ++x
//x = 5
4 + ++x + x--
^^^
|
--> x = 6
--> expression = 5
Next ++x is evaluated, as prefix increment also has higher precedence than the addition, so we have to resolve it before the expression a + b. We aren't concerned with x-- yet, since we've not gotten to it.
Thus, the prefix increment will increase the value of x from 5 to 6 and then return that new value.
3. Addition (x++) + (++x)
//x = 6
4 + 6 + x--
^^^^^
|
--> expression = 10
We've resolved the higher priority expressions, so it's time for the addition. Which is simple 4 + 6 = 10.
4. Post-decrement x--
//x = 6
10 + x--
^^^
|
--> expression = 6
--> x = 5
We're reached another a + b construct but the postfix decrement x-- is higher priority, so we solve that first. Current value of x is 6 and we return that, then do the decrement of x to 5.
5. Addition ((x++) + (++x)) + (x--)
//x = 5
10 + 6
^^^^^^
|
--> expression = 16
Finally, another simple addition after everything with higher precedence is resolved: 10 + 6 = 16
You could take a table for the values, one for x with values for the actual/post or pre and actual value.
Then take according to the order of opperends the value and add this values.
let x = 4
console.log(x++ + ++x + x--); // 16
post pre post increment
x 4 5 5 6 6 5 different values
value 4 6 6 values for addition
let x = 4
console.log(x++ + ++x + x--); // 16
This question already has answers here:
How to format numbers? [duplicate]
(17 answers)
Closed 3 years ago.
I'm trying to create a function that will format a number received from the user's input so that it will add commas in the right places. For example, a 1000 becomes a 1,000. A 1000000 becomes a 1,000,000 an so on.
var formatNumber = function (num) {
var numSplit, dec, int;
num = Math.abs(num);
num = num.toFixed(2);
numSplit = num.split('.');
int = numSplit[0];
dec = numSplit[1];
if (int.length > 3 && int.length <= 6) {
int = int.substr(0, int.length - 3) + ',' + int.substr(int.length - 3, 4);
} else if (int.length > 6) {
int = int.substr(0, int.length - 6) + ',' + int.substr(int.length - 6, int.length - 4) + ',' + int.substr(int.length - 3, 7);
}
return int + '.' + dec
}
The function works great for numbers with up to 7 digits. 1 million turns into 1,000,000.00 perfectly, but above that it adds another zero, so a 10 million becomes 10,0000,000.00 . How can this be fixed?
Here's a codepen: https://codepen.io/samivino/pen/ZEzRjjy
P.s.- Numbers higher than 999,999,999 are not relevant, so there's no need to add more that 2 commas.
You can simply use toLocaleString()
var number = 1000000;
var formatted = number.toLocaleString();
console.log(formatted) //1,000,000
Read here for more information on how to use it.
I came across this example of a recursive function in a textbook. I can see there are other threads on this site that ask a question about this very example from Eloquent JavaScript but that user's difficulty in understanding the example was to do with not understanding how functions are invoked in general.
function findSolution(target){
function find(start, history){
if(start == target)
return history
else if(start > target)
return null
else
return find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)")
}
return find(1, "1");
}
You supply a target number to the findSolution function, and it executes the inner function, find, which calls itself until it finds a way to reach the target number by adding 5 or multiplying by 3. Say I supply the number 13 as a target to reach. The parameters increment as follows.
Start = 1 + 5, History = "(1 + 5)"
Start = 6 + 5, History = "(1 + 5) + 5"
Start = 11 + 5, History = "(1 + 5) + 5) + 5"
Start becomes 16, and this is higher than 13, so this will return null. So the find function tries to multiply start by 3 instead of adding 5, going back to 11...
Start = 11 * 3, History = "(1 + 5) + 5) * 3"
This is also too high, and will so return null. Surely the function stops here, right??
When I test it out though, console logging the start values each time find recursively calls itself, it continues to call itself until it reaches number 13. The start values the function cycles through after 33 are:
18
3
8
13
But how is any of this possible? Shouldn't the function just return false after it reaches 16 and 33?
Console.log history just before the base case. That will help to understand how it works
There is a syntax error in your (the) example code. It should appear like this:
function findSolution(target){
function find(start, history){
if(start == target)
return history
else if(start > target)
return null
else
return (find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)"))
}
return find(1, "1");
}
(Note the structure of the last return in the inner function.)
When running the updated function with an input of 13, I see this in the console:
(((1 * 3) + 5) + 5)
items = 3;
$('#div').html(items + 1 + ' - ' + items + 3);
Trying to make #div display 4 - 6, but it instead shows 4 - 33. What am I missing?
As to why it happened:
first the parser reads items + 1, so fine and dandy, it's 4
then it concatenates with ' - ', so now you have 4 -
then it sees + items, at this moment, you are dealing with String, so it concatenates with 3 (as items is 3), so you have 4 - 3
then you have another concatenation with 3, but the left operand is a string, so the right operand is type casted into String as well, so you have 4 - 33
To achieve what you want, you need to enclose the inner operations:
$('#div').html((items + 1) + ' - ' + (items + 3));