I am practicing solving problems with recursion for a class.
I am solving the problems on this site : http://www.w3resource.com/javascript-exercises/javascript-recursion-functions-exercises.php
The question I am referring to is stated : Write a JavaScript program to get the integers in range (x, y).
Example : range(2, 9)
Expected Output : [3, 4, 5, 6, 7, 8]
Before looking at the solution I came up with this:
var range = function (start, end) {
var result = [];
var accumulator = start;
var accumulate = function () {
accumulator++;
if (accumulator === end) {
return;
} else {
result.push(accumulator);
}
accumulate();
};
accumulate();
return result;
};
The solution on the site is this:
var range = function(start_num, end_num)
{
if (end_num - start_num === 2)
{
return [start_num + 1];
}
else
{
var list = range(start_num, end_num - 1);
list.push(end_num - 1);
return list;
}
};
Is my solution technically still recursive? I had a similar answer on a quiz recently and I was told my solution is essentially iterative.
Though you use recursion, you have simply written a loop in the form of recursion.
I am going to answer this from the purely academical standpoint. If you want to avoid the intermediate state (result) and use purely functional constructs, I would write it like this
function range(start, end) {
function recRange(current, end) {
if (current > end)
return [];
return [current].concat(recRange(current + 1, end));
}
return recRange(start + 1, end - 1);
}
console.log(range(2, 9));
// [ 3, 4, 5, 6, 7, 8 ]
If you see here, we create a new function within the range function, which recursively creates a new array on every iteration (remember: this is not highly performant code, you can simply use loops and be done with this problem efficiently).
The base condition of the recursion is current < end. Once that is met, the recursion stops and an empty array is returned. In all the levels, a new array with the current value is concatenated with the result of the recursive call. So, the evaluation of the calls are roughly understood like this
[3].concat(recRange(3 + 1, end));
[3].concat([4].concat(recRange(4 + 1, end)));
...
at the end, when the recursion unwinds, the values will be like this
[3].concat([4].concat([5].concat([6].concat([7].concat([8].concat([]))))))
[3].concat([4].concat([5].concat([6].concat([7].concat([8])))))
[3].concat([4].concat([5].concat([6].concat([7, 8]))))
[3].concat([4].concat([5].concat([6, 7, 8])))
[3].concat([4].concat([5, 6, 7, 8]))
[3].concat([4, 5, 6, 7, 8])
[3, 4, 5, 6, 7, 8]
and that will be returned as the result.
To make your solution recursive, it should return some value and somehow combine the result of the recursive call to form the return value of the original call.
Let me illustrate that with an example, by modifying your solution:
var range = function (start, end) {
var accumulate = function (accumulator) {
if (accumulator === end - 1) {
return [accumulator]; // Stop condition
} else {
// Recursive block
var result = accumulate(accumulator+1); // recursive call
result.unshift(accumulator); // combine result
return result
}
};
return accumulate(start);
};
The modified accumulate function will return a one-element list for the stop condition, the simplest case it handles, where accumulator reaches the last value to return.
In the example range(2,9), the stop condition will return [8].
Then in the caller, the recursive block
var result = accumulate(accumulator+1);
result.unshift(accumulator);
return result
will take the list [8], and preprend the current value of accumulator (7), so it'll return [7,8].
...and the caller of accumulator(7), will receive [7,8] and preprend the value 6 to the list, to return [6,7,8].
At the end, the original call to accumulator(2) will generate the expected result [2,3,4,5,6,7,8].
Is my solution technically still recursive?
Yes. You're using tail recursion; however, since no arguments are being passed to accumulate() I can see why someone may say it's essentially iterative. You could easily replace your recursive call with a loop. Recursive algorithms typically leverage the stack.
Because of Javascript's closures, it is harder to understand the concept of recursion in Javascript compared to other languages like C++ or Java or C#.
To understand recursion, you must first understand recursion. :)
Related
Don't understand why I have to make the assignment on line 28 to make the code work! Lines 17 to 21 is where I get the results.This is a very basic solution - more interested in why the code works.
//Given a list of non-negative integers and a target sum, find a pair of numbers that sums to the target sum.
function findPairForSum(integers, target)
{
// your solution here
var integerPairArray = [];
// first have the first element as one of the pairs
var firstInteger = integers[0];
// will store the sum of integers
var sum = 0;
// iterate through the remaining elements
for(var index = 1; index < integers.length; index++)
{
// add each to the first element and compare the result with the target
sum = firstInteger + integers[index];
// if true then return the pair in an array
if(sum === target)
{
integerPairArray.push(firstInteger, integers[index]);
break;
}
// if the end of the array is reached and there is no result
if(index === integers.length - 1 && sum !== target)
{
// remove the first element from the array
integers.shift();
// repeat the loop
integerPairArray = findPairForSum(integers, target);
}
}
return integerPairArray;
}
// example
var pair = findPairForSum([3, 34, 4, 12, 5, 2], 17);
console.log(pair); // --> [12, 5]
Since the question has comments, and no answers, I will endeavor to provide an answer based on the comments made .#Solomon P Byer really helped me understand my code! Thank you!
The final return statement from the findPairForSum(integers, target) declaration will go to this function call/expression - var pair = findPairForSum([3, 34, 4, 12, 5, 2], 17); - made outside the function.
Because I made a recursive call within the findPairForSum(integers, target) function, the final return statement will initially go to the call within the function. And because it is a return statement, it has to be ‘caught’ as #Solomon P Byer mentioned.
It is caught by the integerPairArray variable and then the final return statement in the function returns the answer to the function call made outside the function and we get the answer! Whew!
If I have a function like _.transform.
Somewhere within the iteratee function I encounter an error; how do I exit from the _.transform function?
i.e.
{
try {
fs.readFileSync('dog_pics');
} catch(e) {
return;
}
}
What about _.map? Which expects return statements.
_.transform callback can return false in order to stop iterating.
From lodash examples:
_.transform([2, 3, 4], function(result, n) {
result.push(n *= n);
return n % 2 == 0;
});
// → [4, 9]
As you can see, iteration breaks on third step, when n === 3
_.map and _.reduce doesn't support iteration stopping
Since _.transform builds a new return object, returning without setting a pushing onto the result would allow you to "jump" out of that iteration.
(I haven't actually tested this code.)
I'm working through Eloquent Javascript and I'm having trouble understanding something. Perhaps I've missed something along the way. This is the solution given for chapter 5 (higher-order functions), exercise 1, which takes the elements in the different arrays and puts them all in a single array:
var arrays = [[1, 2, 3], [4, 5], [6]];
console.log(arrays.reduce(function(flat, current) {
return flat.concat(current);
}, []));
My problem is: I have absolutely no clue why the arguments "flat" and "current" work in this situation. The entire chapter reads through assuming the reader understands what's going on here but I have absolutely no idea why this works. It doesn't appear that "flat" and "current" are defined anywhere. Another short example is this one where the author explains how the reduce method works (problem area in bold):
function reduce(array, combine, start) {
var current = start;
for (var i = 0; i < array.length; i++)
current = combine(current, array[i]);
return current;
}
**console.log(reduce([1, 2, 3, 4], function(a, b) {
return a + b;
}, 0));**
Where in the world did "a" and "b" come from and why does this piece of code work? Any help would be much appreciated, thank you.
flat and current don't need to be declared anywhere, they are parameters to the anonymous function that is passed to Array.reduce.
One way to illustrate this is to modify your second example to use Array.reduce directly using an anonymous function with parameters a and b. Look at this:
[1, 2, 3, 4].reduce(function(a, b) {
console.log("a: " + a + " b: " + b);
return a + b;
});
The console will now show:
a: 1 b: 2
a: 3 b: 3
a: 6 b: 4
10
What's happening is that the anonymous function(a, b) {...} is called with (1, 2), which returns 3, which is passed in again (3, 3) which returns 6, which is passed in as the first argument (6, 4), which returns the final answer 10.
Another illustration is to use a second argument to Array.reduce, say 10, to see what's going on. That 10 is used as the initialValue. So:
[1, 2, 3, 4].reduce(function(a, b) {
console.log("a: " + a + " b: " + b);
return a + b;
}, 10);
The trace is:
a: 10 b: 1
11 b: 2
13 b: 3
16 b: 4
20
You can work out how that happened.
Yes, reduce can be a little confusing in the beginning. It is a native function that takes two parameters. One is a callback function and the other one is any value.
The idea is that in the callback function you can use the values of the array one at a time to process a result. To do that it iterates over the array values and passes them to the callback function you defined one at a time and for every loop it takes the value of the last loop and passes it as well.
Let's say you want to sum all numbers in an array:
//your array
var numbers = [4,7,3];
//your initial value
var initialValue = 0;
//your function
function sum(iteratingValue, arrayValue) {
return iteratingValue + arrayValue;
}
var result = numbers.reduce(sum, initialValue);
Now, you can name your callback function parameters whatever you like, a and b, start and finish, fish and duck. It won't matter, reduce will pass the values in the same order.
Here is the definition by MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
reduce executes the callback function once for each element present in the array, excluding holes in the array, receiving four arguments: the initial value (or value from the previous callback call), the value of the current element, the current index, and the array over which iteration is occurring.
First, let us touch the core of the question. Let's suppose you have a function, like this:
function func1(myfunc, arr) {
//Do something, which will result in having variables called param1 and param2
myfunc(param1, param2);
}
Let's see what happens. func1 takes myfunc and arr as parameters. myfunc will be passed when func1 is called. arr is an array.
Now, let's suppose you call it this way:
func1(function(a, b) {
//do something with a and b
}, [1, 2, 3, 4]);
You are calling func1, by passing a function and an array. The array is obvious, so let's see the function. The function expects two parameters and will do something with them. You do not have to define a or b when you call func1, since it is func1's internal job to create and initialize them. So, func1 will do its internal things and call your function passed as a parameter. Now, let's see your example:
var arrays = [[1, 2, 3], [4, 5], [6]];
console.log(arrays.reduce(function(flat, current) {
return flat.concat(current);
}, []));
Here, you call arrays.reduce (which is very similar to func1 in the general description). You pass a function and an array. Again, the array is obvious, but the question is, how flat and current are defined. The answer is that it is arrays.reduce's internal job to create and initialize them. As about the reduce prototype function, you can read more about it here.
I just signed up in codewars and I'm trying the first kata. This is the question:
Write a function to multiply a number (x) by a given number (y) a certain number of times (n). The results are to be returned in an array.
eg.
multiplyBy(2, 4, 6);
The output is: [8, 32, 128, 512, 2048, 8192]
I believe my code is write, when I do console.log I get the array that the exercise is asking for, but it won't let me proceed. I'd appreciate some help, thanks!
var array = [];
function multiplyBy(x, y, n) {
while (x<2049){
var z = x*y*n;
var x = z;
array.push(z)
}
}
multiplyBy(2,2,2);
console.log(array);
return array;
You have a few things going on outside your function which make it only work one time. Make sure that you keep everything inside the function until the last return
function multiplyBy(x, y, n) {
var array = []; // var this inside your function
for (; n > 0; --n) { // the loop is only supposed to happen n times
x = x * y; // you can reuse this variable (x)
array.push(x);
}
return array; // return statement should be inside your function
}
// example of logging the returned value
console.log(multiplyBy(2, 4, 6)); // [8, 32, 128, 512, 2048, 8192]
Your while loop also was hardcoded to x<2049, but this isn't always the case as it depends on the n parameter given to the function
it won't let me proceed
There are 3 issues in the code you posted that probably prevent you from proceeding,
The return array is probably throwing a syntax error because it's outside a function
In your code, calling multiplyBy several times appends the new values onto the end of the previous array
They are probably testing your function against other sets of values to check it works as expected, which is not true in your function, i.e. you gave the example inputs of 2, 4, 6 but used 2, 2, 2 in your own code
As a final note, try to get into the habbit of indenting your code, it'll save you headaches reading it later as it lets you quickly see where blocks begin and end
Your return is outside the function. And all calls to multiplyBy populate the same array. And your logic is flawed.
Probably, it should be
function multiplyBy(x, y, n) {
var array = [];
while (n--) array.push(x *= y)
return array;
}
console.log(multiplyBy(2,4,6));
Or, in ECMAScript 6,
var multiplyBy = (x, y, n) => Array(n).fill().map(a => x*=y);
ramove the return at the end, this must be used in function to return something, if not used the function will return undefined.
Look at this (single-line solution):
function multiplyBy(x,y,n) {
return Array.apply(null, new Array(n)).map(function(v, i) { return x * Math.pow(y, i + 1); });
}
DEMO
While going through Eloquent Javascript (Chapter 6) there is a reference to higher-order functions in Javascript. While there is an example provided in Chapter 3, I believe it could be a bit simpler since I still don't fully understand the concept. After searching the web I can't seem to find any succinct examples of a higher-order function.
I'd like to see a basic/simple higher-order function in Javascript that will explain the concept.
Higher functions are concepts from functional programming. In briefly, a higher function is a function which takes another function as parameter. In javascript, some higher functions are added recently.
Array.prototype.reduce
//With this function, we can do some funny things.
function sum(array){
return array.reduce(function(a, b){ return a + b; }, 0);
}
So, in the above sample, reduce is a higher order function, it takes another function, the anonymous function in the sample, as a parameter. The signature of reduce looks like this
reduce(func, init);
//func is a function takes two parameter and returns some value.
// init is the initial value which would be passed to func
//when calling reduce, some thing happen
//step 1.
[1, 2, 3, 4, 5].reduce(function(a, b){ return a + b }, 0);
//step 2.
[2, 3, 4, 5].reduce(function(a, b){ return a + b}, 0 + 1);
//step 3.
[3, 4, 5].reduce(function(a, b){ return a + b}, 0 + 1 + 2);
//...
As you can see, reduce iterate an array, and apply the func with init and first element of that array, then bind the result to init.
Another higher order funciton is filter.
Array.prototype.filter
//As the name indicates, it filter out some unwanted values from an Aarry. It also takes a function, which returns a boolean value, true for keeping this element.
[1, 2, 3, 4, 5].filter(function(ele){ return ele % 2 == 0; });
With the above two examples, I have to say higher order function is not that much easy to understand, especially reduce. But that's not complex, with higher order function, actually your code would be more clean and readable. Take the filter as example, it tells people that it throws all odd numbers away.
Here I'd like to implement a simple filter function to show you how.
function filter(array, func){
var output = [];
for(var i = 0; i < array.length; i++){
if(func(array[i])) output.push(array[i]);
}
return output;
}