This question already has answers here:
How does this recursion work?
(11 answers)
Closed 7 years ago.
This example is from Eloquant javascript and I can't get how it works. I got how basically the recursion works though from other basic examples. Can anyone explain to me know how this works?
It is explained on the link below.
http://eloquentjavascript.net/03_functions.html
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");
}
findSolution(24));
//answer
//"(((1 * 3) + 5) * 3)"
First you need to understand how the returns work for the inner function.
return func(A) || func(B)
If func(A) is not null it's returned, otherwise func(B)
Now our target is 24 and the starting point would be find(1, 1) (the return value of the outer function which triggers the recursive function)
find(1, 1) may have two possible outputs:
A: find(6, (1+5))
or
B find(3, (1*3))
B will be on hold unless we get a null return from A (or reach the target), so we continue with A, the return will be:
Aa: find(11, ((1+5)+5))
or
Ab: find(15, ((1+5)*3))
Again Ab on hold and we continue with Aa which will return:
Aa1: find(16, (((1+5)+5)+5))
Aa2: find(33, (((1+5)+5)*3))
Aa2 is bigger than target (24) so it will never continue. So we continue with Aa1 which will return 21 and then 25 which passes the target and so returns null. So we go back to Ab which returns 45 > target. So A returns null anyway and now we try B:
Ba: find(8, ((1*3)+5))
Bb: find(9, ((1*3)*3))
Continue with Ba which then returns:
Ba1: find(13, (((1*3)+5)+5))
Ba2: find(24, (((1*3)+5)*3))
We continue with Ba1 which will return 18 and then 23 and then 28 which is bigger than target and so null. So go back to Ba2 which is 24 == target and so finishes the calculation and returns its history which is:
(((1*3)+5)*3)
jsfiddle DEMO
You can see the log of all the end points (when null reached or finally when a match found).
EDIT:
This is how the function will execute:
//instead of find I use f
findSolution(24) >
f(1, 1) >
f(6, (1+5)) >
f(11, ((1+5)+5)) >
f(16, (((1+5)+5)+5)) >
f(21, ((((1+5)+5)+5)+5)) >
f(26, (((((1+5)+5)+5)+5)+5)) > NULL
f(63, (((((1+5)+5)+5)+5)*3)) > NULL
f(48, ((((1+5)+5)+5)*3)) > NULL
f(33, (((1+5)+5)*3)) > NULL
f(18, ((1+5)*3)) >
f(23, (((1+5)*3)+5)) >
f(28, ((((1+5)*3)+5)+5)) > NULL
f(69, ((((1+5)*3)+5)*3)) > NULL
f(54, (((1+5)*3)+5)) > NULL
f(3, (1*3)) >
f(8, ((1*3)+5)) >
f(13, (((1*3)+5)+5)) >
f(18, ((((1*3)+5)+5)+5)) >
f(23, (((((1*3)+5)+5)+5)+5)) >
f(28, ((((((1*3)+5)+5)+5)+5)+5)) > NULL
f(69, ((((((1*3)+5)+5)+5)+5)*3)) > NULL
f(54, (((((1*3)+5)+5)+5)*3)) > NULL
f(39, ((((1*3)+5)+5)*3)) > NULL
f(24, (((1*3)+5)*3)) > MATCH
1. function findSolution(target){
2. function find(start, history){
3. if (start == target)
4. return history;
5. else if (start > target) {
6. return null;
7. }
8. else
9. return find(start + 5, "(" + history + " + 5)") ||
10. find(start * 3, "(" + history + " * 3)")
11. }
12. return find(1, "1");
13. }
14.
15. findSolution(24);
When line 15 calls the function findSolution, 24 is passed in for target. Inside the function findSolution, another function find is defined. This function is then called using find(1, "1") on line 12, which starts the recursion. On the first pass of this recursion, a check is made to see if the recursion is completed. This happens when start is equal to target (line 3), which is the value given previously for findSolution (on line 15). In this case, it won't on the first pass, so it proceeds to the next part on line 5. On this line it checks if the start value has gone beyond the target, and if so, returns null. If NOT, then it proceeds to line 9, which recursively calls find with the current start value (1 on the first pass), plus 5 (so 6), and if fails (null is returned [see line 6]), the second call on line 10 occurs because of the || operator. This tries start*3, and on the first pass, this is 1*3, or 3. This keeps going until it has gone as far as it can adding to or multiplying the start value.
In a nutshell, the recursion keeps going via find while start does not reach the target. It ends when either the start value is an exact match to target (line 3), or if the target cannot be reached because of the test on line 5, which doesn't allow start + 5 or start * 3 to go beyond it.
Related
var printRangeUpDown = function(min, max) {
if (min === max) {
console.log('condition met ' + min);
return
}
console.log('low to high ' + min);
printRangeUpDown(min + 1, max);
console.log('high to low ' + min);
};
printRangeUpDown(4, 10);
logs 4,5,6,7,8,9,10,9,8,7,6,5,4
Can someone explain why the console.log below printRangeUpDown makes it start logging backward? I understand that low will console log 4,5,6,7,8,9,10(base case) ... but I do not understand why console logging below the recursive makes it print 9,8,7,6,5,4 back to min
Imagine your stack of recursive calls (the call stack). The child function must complete before the parent can continue.
So at the point the base case is reached (i.e. min == max), the first half of each recursive call has been executed and each waits for its child to return.
The base case does not recurse it just returns. Now the second half of each function is executed. Starting with the most recently called (min = 9) and working towards the first to be called (min = 4). This is called LIFO or Last In First Out.
The reason for the values printed is that for each function call the input arguments are preserved until it returns and so what you are seeing is the same values that were printed on the way towards the base case are printed when returning to the first invocation of the function.
If we add a space for each recursive call then it becomes simple to see how the first and last, second and second to last etc. Call match their values.
4, // first invocation
5, // second
6, // third
7, // fourth
8, // fifth
9, // sixth
10, (base case)
9, // sixth
8, // fifth
7, // fourth
6, // third
5, // second
4 // first invocation
Because it is a stack (first in last out).
When you call printRangeUpDown(4, 10) from the very beginning, it goes to printRangeUpDown(min + 1, max);, the program will wait for this function to return to go forward.
Program goes to printRangeUpDown(5, 10), same as above, wait for printRangeUpDown(6, 10);.
Program goes to printRangeUpDown(10, 10), finally, the first return.
Then printRangeUpDown(9, 10) will return, because (10, 10) is returned.
Then printRangeUpDown(8, 10) will return, because (9, 10) is returned.
Finally, printRangeUpDown(4, 10) returned.
Much apologies for the vague title, but I need to elaborate. Here is the code in question, which I read on http://ariya.ofilabs.com/2013/07/prime-numbers-factorial-and-fibonacci-series-with-javascript-array.html:
function isPrime(i) {
return (i > 1) && Array.apply(0, Array(1 + ~~Math.sqrt(i))).
every(function (x, y) {
console.log(x + ' ' + i % y);
return (y < 2) || (i % y !== 0)
});
}
isPrime(23);
isPrime(19);
isPrime(188);
Just for fun, I added those logs so we can see some output:
undefined NaN
undefined 0
undefined 1
undefined 2
undefined 3
undefined NaN
undefined 0
undefined 1
undefined 1
undefined 3
undefined NaN
undefined 0
undefined 0
This is the first time I have every seen apply and every, so bear with me, but my understanding is that apply basically calls the Array function, where the first argument is the substitution for its this and the second is the output...Never would think that would be useful, but this function seems to work, so...
Here, they seem to be creating an array of length equal to the square root of the number in question. I suppose that makes sense because the square root would be the largest possible factor of the number in question.
OK, so from here, if we were to log that array for, say, the first number, it would look like this:
> var i = 23;
undefined
> Array.apply(0, Array(1 + ~~Math.sqrt(i)));
[ undefined, undefined, undefined, undefined, undefined ]
Great, so it is an array of five undefined. Ok, fine, so from here, the every method is supposed to check whether every element in that array passes the callback function test (or whatever).
The Microsoft documentation specifies three possible arguments for the every method:
value
index
array
Therefore, in this example x is the value, i.e. undefined, and y is the index.
Our output agrees with that conclusion. However, I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?), the || operator here (if the first test passes, does the every loop stop?), and just generally how this works.
EDIT
the log should be with an x, not a y. my mistake:
console.log(y + ' ' + i % y); -> console.log(x + ' ' + i % y);
EXPLANATION
So, how did I come across this code, you ask? Well, of course, the simplest way to check for a prime in Java would be like this:
public static boolean isPrime(double num) {
for (double i = 2.0; i < sqrt(num); i++) {
if (num % i == 0.0) {
return true;
}
}
return false;
}
or Python
def isPrime(num):
x = 2
isPrime = True
while x < math.sqrt(num):
if num % x == 0:
isPrime = False
break
x = x + 1
return isPrime
or js
function isPrime(n) {
for (var i = 2.0; i < Math.sqrt(n); i++) {
if (n % i === 0.0) {
return false;
}
}
return true;
}
But say I wanted to check for the largest prime factor of a number like 600851475143 These looping methods would take too long, right? I think this "hack", as we are describing it, may be even less efficient, because it is using arrays instead of integers or floats, but even still, I was just looking for a more efficient way to solve that problem.
The code in that post is basically crap. Teaching people to write code while simultaneously using hacks is garbage. Yes, hacks have their place (optimization), but educators should demonstrate solutions that don't depend on them.
Hack 1
// the 0 isn't even relevant here. it should be null
Array.apply(0, Array(1 + ...))
Hack 2
// This is just Math.floor(x), but trying to be clever
~~x
Hack 3
// this is an outright sin; totally unreadable code
// I bet most people don't know the binding precedence of % over +
y + ' ' + i % y
// this is evaluated as
y + ' ' + (i % y)
// example
2 + ' ' + (5 % 2) //=> "2 1"
I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?),
No. A return only return the function the statement exists in
the || operator here (if the first test passes, does the every loop stop?)
No. Array.prototype.every will return false as soon as the callback returns a false. If a false is never returned from the callback, .every will return `true.
function isEven(x) { return x % 2 === 0; }
[2,4,5,6].every(isEven); //=> false, stops at the 5
[2,4,6].every(isEven); //=> true
Here's an example of .every short circuiting
[1,2,3,4,5,6].every(x=> {console.log(x, x<4); return x<4;});
// 1 true
// 2 true
// 3 true
// 4 false
//=> false
See how it stops once the callback returns false? Elements 5 and 6 aren't even evaluated.
... and just generally how this works.
&& kind of works like Array.prototype.every and || kind of works like Array.prototype.some.
&& will return false as soon as the first false is encountered; in other words, it expects every arguments to be true.
|| will return true as soon as the first true is encountered; in other words, it expects only some argument to be true.
Relevant: short circuit evaluation
I am trying to understand, how recursion works. I got the basic idea, but the details remain unclear. Here is a simple example in javascript:
function sumTo(n){
if (n > 1){
return n + sumTo(n-1)
} else {
return n
}
}
sumTo(3);
It is supposed to count all numbers in 3 and the result is 6 (1 + 2 + 3 = 6), but I don't get, how it works.
OK, we start from if condition. 3 > 1, so we return n and call the function again, but what will be inside if brackets?
Does it look like this:
3 + sumTo(2) // 3 - 1 = 2
Or we don't do anything with n, and wait for the next function:
3 + sumTo(n - 1) // n will come later
I was told that the last function will return 1 to the upper one, but I don't get what it will do with this 1.
If there is some step-by-step explanation for ultimate dummies, please share.
I know there is a lot of similar questions, but found no help.
UPD: It looks like I finally found out how it works, spending two days and asking everyone I could. I'll try to explain for ultimate dummies like me. That's gonna be long, but I hope somebody with the same troubles will find this post and it will be useful.
At first I'd like to show another example of recursion, which is a little easier. I found it at http://www.integralist.co.uk/posts/js-recursion.html and changed values from (1, 10) to (2, 3).
function sum(x, y) {
if (y > 0) {
return sum(x + 1, y - 1);
} else {
return x;
}
}
sum(2, 3);
When we start the function, we check the if condition y > 0. Y is 3, so the condition is true. So we return sum(x + 1, y - 1), i. e. sum(2 + 1, 3 - 1), i. e sum(3, 2).
Now we need to count sum(3, 2). Again, we go to the beginning and start from condition y > 0. Y is 2, so the condition is true. So we return sum(x + 1, y - 1), i. e. sum(3 + 1, 2 - 1), i. e sum(4, 1).
Now we need to count sum(4, 1). One more time, we check the condition y > 0. Y is 1, the condition is true. We return sum(x + 1, y - 1), i. e. sum(4 + 1, 1 - 1), i. e sum(5, 0).
Now we need to count sum(5, 0). We check the condition y > 0 and it is false. According to the if-else in the function, we return x, which is 5. So, sum(2, 3) returns 5.
Now let's do the same for sumTo();
function sumTo(n){
if (n > 1){
return n + sumTo(n-1)
} else {
return n
}
}
sumTo(3);
Starting from sumTo(3). Checking the n > 1 condition: 3 > 1 is true, so we return n + sumTo(n - 1), i. e. 3 + sumTo(3 - 1), i. e. 3 + sumTo(2).
To go on, we need to count sumTo(2).
To do this, we again start the function from checking the n > 1 condition: 2 > 1 is true, so we return n + sumTo(n - 1), i. e. 2 + sumTo(2 - 1), i. e. 2 + sumTo(1).
To go on, we need to count sumTo(1).
To do this, we again start the function and check the n > 1 condition. 1 > 1 is false, so, according to if-else, we return n, i. e. 1. Thus, sumTo(1) results in 1.
Now we pass the result of sumTo(1) to the upper function, sumTo(2), where we earlier stated that we needed sumTo(1) to go on.
SumTo(2) returns n + sumTo(n-1), i. e. 2 + sumTo(2 - 1), i. e. 2 + sumTo(1), i. e. 2 + 1. Thus, sumTo(2) results in 3.
Now we pass the result of sumTo(2) to the upper function, sumTo(3), where we earlier stated that we needed sumTo(2) to go on.
SumTo(3) returns n + sumTo(n-1), i. e. 3 + sumTo(3 - 1), i. e. 3 + sumTo(2), i. e. 3 + 3. Thus, sumTo(3) finally results in 6. So, sumTo(3) returns 6.
My mistake was that everywhere I tried to insert 3 instead of n, while n was decreasing to 1.
Thanks to everyone, who responded to this question.
You can understand like
sumTo(3);
returns => 3 + sumTo(2) // n is greater than 1
returns => 2 + sumTo(1)
returns => 1 // 1 as n is not greater than 1
That's right, sumTo(n) waits until sumTo(n-1) is completed.
So, sumTo(3) waits for sumTo(2),
sumTo(2) waits for sumTo(1),
then sumTo(1) returns 1,
sumTo(2) returns 2 + 1
and sumTo(3) returns 3 + 2 + 1
Showing work:
sumTo(4) = (4 + 3) + (2 + 1) = 10 // 4 + sumTo(3). function called four times
sumTo(3) = (3 + 2) + 1 = 6 // 3 + sumTo(2). called three times
sumTo(2) = (2 + 1) = 3 // 2 + sumTo(1). called twice
sumTo(1) = (1) = 1 // called once
It will probably be easier for you to wrap your head around if you think of it backwards, from the ground up instead of from the top down. Like this:
sumTo(1) = 1 + sumTo(0) = 1
sumTo(2) = 2 + sumTo(1) = 3
sumTo(3) = 3 + sumTo(2) = 6
sumTo(4) = 4 + sumTo(3) = 10
Notice how now you can keep adding to the list, and it will be easy to calculate the previous one because you're just adding the two sums.
The chain of events is as follows:
sumTo(3) adds 3 and calls sumTo(2) which also calls sumTo(1) and returns 3, giving you a grand total of 6.
Does that make sense? I'll gladly elaborate or clarify if anyone has questions.
An important question to understand is why to use recursion and when to use recursion. A good discussion on the subject can be found here: When to use recursion?
A classic example of recursion is the fibonacci sequence. Another good example would be traversing a directory of files on your computer, for example if you wanted to search every file inside of a folder that contains other folders. You can also use recursion to factor exponents.
Consider an easier example of recursion:
function multiplyBy10(i) {
if ( !i ) return 0;
return 10+multiplyBy10(i-1);
}
This function will multiply the number by 10 using recursion. It's good to get a grasp on when recursion is practical because there are times it makes things easier for you. However, it's best to keep things simple and not confuse yourself wherever possible. :)
I understand that "a" solution is:
function Factorial(number)
{
if(number == 0 || number == 1){
return 1;
}
return number * Factorial(number -1);
}
I want to understand what exactly is going on. I understand what is going on all the way to the last part when number == 1.
If we were to take a simple example of say 3!
3 is not equal to 0 or 1 so we return 3 * Factorial(2)
2 is not equal to 0 or 1 so we return 2 * Factorial(1)
1 is equal to 1 so we return 1
How do we know when to stop? Is it the fact that we return 1 that tells the function to stop?
If that is the case, why does the function not stop when we first return 3 * Factorial(2)? Is it because it's returning a function so that it must continue until it no longer returns a function?
Thank you
I think you have to understand the logic of factorial.
So factorial is just products, indicated by an exclamation mark ie, if you write
0! = 1
1! = 1
2! = 2*1
3! = 3*2*1
4! = 4*3*2*1
5! = 5*4*3*2*1
Hope you find the pattern, so you can write the above factorials as:
0! = 1
1! = 1
2! = 2*1!
3! = 3*2!
4! = 4*3!
5! = 5*4!
So in your function you are using the similar logic.
Now in your function
if(number == 0 || number == 1)
{
return 1;
}
The above logic is to cover the first two cases i.e, 0! and 1! And
return number * Factorial(number -1);
is for the rest of the numbers.
So you are using the recursive technique of solving the factorial problem.
To understand recursion, lets take a number say 5 i.e., we want find the value of 5!.
Then first your function will check
if(number == 0 || number == 1)
which is not satisfied, then it moves to the next line ie,
return number * Factorial(number -1);
which gives
5*Factorial(5-1) which is equal to 5*Factorial(4)
Now on subsequent calls to your Factorial function it will return the value like below:
5*(4*Factorial(4-1)) which is equal to 5*(4*Factorial(3))
5*(4*(3*Factorial(3-1)) which is equal to 5*(4*(3*Factorial(2)))
5*(4*(3*(2*Factorial(2-1)))) which is equal to 5*(4*(3*(2*Factorial(1))))
Now when it returns factorial(1) then your condition
if(number == 0 || number == 1)
is satisfied and hence you get the result as:
5*4*3*2*1 = 120
On a side note:
Beware that factrial is used only for positive integers.
Recursion relies on what is called a base case:
if(number == 0 || number == 1){
return 1;
}
That if statement is called your base case. The base case defines when the recursion should stop. Note how you are returning 1 not returning the result of a call to the function again such as Factorial(number -1)
If the conditions for your base case are not met (i.e. if number is NOT 1 or 0) then you proceed to call the function again with number * Factorial(number - 1)
If that is the case, why does the function not stop when we first return 3 * Factorial(2)?
Your simple example of 3! can be elaborated like this :
return 3 * Factorial(2)
will then be replaced by
return 3 * (2 * Factorial(1))
which then will be replaced by
return 3 * (2 * 1) // = 6 Hence 6 is returned at last and recursion ends.
How do we know when to stop?
When all your Factorial(value) is replaced by a returned value we stop.
Is it the fact that we return 1 that tells the function to stop?
In a way, yes. Because it is the last returned value.
It is called recursion.
This function is called like this
var result = Factorial(3);
in Factorial function
First time
return 3*Factorial(2);
Now here return statement doesnt get executed insted Factorial is called again..
so second time
return 2*Factorial(1);
again in Factorial(1)
Third time
return 1;
So go to second
return 2*1;
Next to first
return 3*(2*1);
Finally
var result = 3*2*1 = 6.
The function is recursing (calling itself) - and taking one from "number" each time.
Eventually (as long as its a positive integer you call it with, otherwise you'll probably get an infinite loop) you'll always hit the condition (number == 1) so instead of recursing further, it'll return 1 rather than call the function again.
Then, once you have hit the bottom (1), it'll start to run the function and work back up the other way along the function call stack, using the previous result each time:
1 = 1
(2*1) = 2
(3*2) = 6
(4*6) = 24
etc
So the final return statement from the function will return the required result
This question already has answers here:
What does the || operator do?
(4 answers)
What does "options = options || {}" mean in Javascript? [duplicate]
(5 answers)
Closed 8 years ago.
I have a piece of JavaScript code that shows:
function(next, feather) {
var l = Number(171) + (next || 0);
var m = Math.max(1, l - 9);
return {
lc: 300 * (l + 1) * m + (5 * feather || 0)
}
}
Now I've simplified it a little bit. But can anyone explain what the "|| 0" does? As far as I can tell it does nothing.
(Notice I replaced a function with Number(171), as that function effectively returns a number, feather is also supposed to be a number, 0 most of the time, 1 sometimes).
If next is falsy, 0 will be used in its place. JavaScript has no default value operator, so users have leveraged this approach, even though the language's creator has called it an abusage.
Well if you know next and feather are numbers, then yes, it has no function. However, if you were to pass in a value like undefined, which is effectively what will happen if you call the function without specifying any parameters, you'll see some difference:
var next = undefined;
console.log(171 + next); // NaN
console.log(171 + (next || 0)); // 171
Of course, this isn't a foolproof method. Passing in null has no effect on the computation, and passing a non-empty string (e.g. "1"), will result in something very different.
variable || 0 looks up the variable, and if it is undefined, null, or empty (i.e. zero), it will use the number 0 instead. This actually makes sense because if it was anything other than zero itself, it would return NaN.
If that didn't make any sense, this should:
undefined * 1 == NaN;
(undefined || 0) * 1 == 0;
If the next is falsy (false-like value) zero is used instead.
E.g.
next || 0
equals something like
if(!next) { return 0 } else { return next; }
It forces false-like values to be an actual zero number.
If the context before the logical or || is falsy (this includes nulls and undefineds), then it will take the value after it. So in your case, if next or feather is not defined or 0, then the value of 0 will be used in those calculations within the parenthesis, essentially the code will read as the following if both are 0 or undefined:
function(next, feather) {
var l = Number(171) + 0;
var m = Math.max(1, l - 9);
return {
lc: 300 * (l + 1) * m + 0
}
}
Using the OR operator || in this scenario is basically short hand for checking weather or not next was included. If it were coming from some sort of number calculation, perhaps it was possible that next was NaN at times (which is always falsy) and so this was the workaround to make it 0.
var l = Number(171) + (next || 0);
A more readable approach would be to test for that case at the inset of the function
if( isNaN(next) )next = 0;
Or to also include other tests as well
if( isNaN(next) || next === null || typeof(next) === "undefined" )next = 0;
The && and || operators in JavaScript will shortcut evaluation. The way it's set up in the example you gave, if 'next' evaluates to a boolean TRUE then that will be added to 'l', otherwise '0' will be added.