You're creating a new array instead of passing it to the recursive call.
Do this instead.
DEMO: http://jsfiddle.net/kDtZn/
function addToArray(array) {
array.push(prompt("Add items to array or 'q' to stop"));
if (array[array.length-1] == 'q') {
array.pop();
document.write(array)
}
else {
addToArray(array);
}
}
addToArray([]);
Now you start with an empty array, and for each recursive call, it passes the same array forward.
Also, I changed it so that it doesn't use .pop() in the if() condition, otherwise you'll always end up with an empty array when it comes time to write it. (The .pop() method actually removes the last item.)
Finally, make sure you're not using document.write after the DOM is loaded. If so, you need to change it to use DOM manipulation methods instead.
You could take a different approach so that you don't need .pop() at all.
DEMO: http://jsfiddle.net/kDtZn/1/
function addToArray(array) {
var item = prompt("Add items to array or 'q' to stop");
if (item == 'q') {
document.body.textContent = array;
} else {
array.push(item);
addToArray(array);
}
}
addToArray([]);
The reason your while loop didn't work is very likely because of the original .pop() issue.
You're creating a new array instead of passing it to the recursive call.
Do this instead.
DEMO: http://jsfiddle.net/kDtZn/
function addToArray(array) {
array.push(prompt("Add items to array or 'q' to stop"));
if (array[array.length-1] == 'q') {
array.pop();
document.write(array)
}
else {
addToArray(array);
}
}
addToArray([]);
Now you start with an empty array, and for each recursive call, it passes the same array forward.
Also, I changed it so that it doesn't use .pop() in the if() condition, otherwise you'll always end up with an empty array when it comes time to write it. (The .pop() method actually removes the last item.)
Finally, make sure you're not using document.write after the DOM is loaded. If so, you need to change it to use DOM manipulation methods instead.
You could take a different approach so that you don't need .pop() at all.
DEMO: http://jsfiddle.net/kDtZn/1/
function addToArray(array) {
var item = prompt("Add items to array or 'q' to stop");
if (item == 'q') {
document.body.textContent = array;
} else {
array.push(item);
addToArray(array);
}
}
addToArray([]);
The reason your while loop didn't work is very likely because of the original .pop() issue.
Your function recreates var array = [] on every loop/recursion. I am not sure if recursion is the right tool for the job in your case - it does not seems like it - but if you're starting out with JavaScript/development and just trying it out then you're fine.
array.push() recursion in JS
Help with Recursive Arrays
recursion - Array decomposing recursive function in JavaScript - Code Review Stack Exchange
recursion - Javascript -> how to recursively add an array of numbers? - Stack Overflow
Hello there,
I am new to JS having a hard time figuring out how does recursion in this code works I know that push in Js almost works like append rather than just push
Code:
function countdown(n){
if(n<=0){
var arr=[];
return arr;}
if(n>0){
var arr=[n];
arr.push(countdown(n-1));
return arr;}}
console.log(countdown(5));
Output
[ 5, [ 4, [ 3, [Array] ] ] ]
Why does it print nested array
Thanks for help in advance;)
If you don't need using recursion, this is an alternative where you can get rid of the second param of the function.
const stringToArray = (str) => {
const result = [];
let wordArray = str.split(' ');
while(wordArray.length > 0) {
result.push(wordArray.join(' '));
wordArray = wordArray.slice(1);
}
return result;
};
const partsArray = stringToArray('Chicago IL 12345 United States');
console.log(partsArray);
If you're targeting a recent javascript engine you can use default parameters which would save you line #2.
Additionally, to improve readability I'd recommend moving the string slicing to its own line, and I'd also use a name other than len to represent the number of words remaining. Clean Code by Robert Martin is a great resource for learning how to improve code readability.
const stringToArray = (str, result = []) => {
const wordArray = str.split(' ');
const numberOfRemainingWords = wordArray.length;
result.push(str);
if (numberOfRemainingWords === 1) {
return arr;
}
const remainingWords = wordArray.slice((-1 * numberOfRemainingWords) + 1).join(' ');
return stringToArray(remainingWords, result);
};
const partsArray = stringToArray('Chicago IL 12345 United States');
console.log(partsArray);
A one-liner that meets all your requirements:
var sum = function(array) {
return (array.length === 0) ? 0 : array[0] + sum(array.slice(1));
}
// or in ES6
var sum = (array) => (array.length === 0) ? 0 : array[0] + sum(array.slice(1));
// Test cases
sum([1,2,3]); // 6
var s = [1,2,3];
sum(s); // 6
sum(s); // 6
Reasoning
- In a recursive call, you need to model your task as reduction to a base case. The simplest base case in this case is the empty array - at that point, your function should return zero.
- What should the reduction step be? Well you can model a sum of an array as the result of adding the first element to the
sumof the remainder of the array - at some point, these successive calls will eventually result in a call tosum([]), the answer to which you already know. That is exactly what the code above does. array.slice(1)creates a shallow copy of the array starting from the first element onwards, and no mutation ever occurs on the original array. For conciseness, I have used a ternary expression.
Breakdown:
sum([1,2,3])
-> 1 + sum([2,3])
-> 1 + 2 + sum([3])
-> 1 + 2 + 3 + sum([])
-> 1 + 2 + 3 + 0
-> 6
You're on the right track, but consider that sum could take an optional second argument (that defaults to zero) that indicates the position to start summing from...
function sum(array, n) {
n ||= 0;
if (n === array.length) {
return 0;
} else {
return array[n] + sum(array, n + 1);
}
}
Rather than pushing the entire returned array from getBreadcrumb into your result, you can instead push the individual array elements from the returned array using the spread syntax (...):
breadcrumbArray.push(...getBreadcrumb(parentPageId))
Note that the above will fail if the array returned by getBreadcrumb() is very large an exceeds the max-argument count that you can pass to the .push() function. You do always have the option of doing what you're currently doing, and then calling .flat(Infinity) on your returned result. This does add an additional pass over your array though which can be avoided.
You can overcome these issues by instead returning a new array, with your returned array spread into that:
function getBreadcrumb(pageId) {
const { id, slug, title, parentPageId } = getParentPage(pageId);
return [{ id, slug, title, parentPageId }, ...(parentPageId ? getBreadcrumb(parentPageId) : [])];
}
The above will create a new array, with your {id, slug, ...} object as the first element, followed by either nothing (if parentPageId is falsy), or the array elements from that array returned by the call to getBreadcrumb(parentPageId))
Here's a non-recursive approach, use a while loop, and re-call getParentPage():
function getBreadcrumb(pageId) {
let breadcrumbArray = [];
let { id, slug, title, parentPageId } = getParentPage(pageId);
breadcrumbArray.push({ id, slug, title, parentPageId });
// while parentPageId === false, execute getParentPage with found id
while ( parentPageId ) {
pageObj = getParentPage(id);
breadcrumbArray.push(pageObj);
// update found id and parentPageId for while loop
id = pageObj.parentPageId;
parentPageId = pageObj.parentPageId;
}
return breadcrumbArray;
}
// okay to ignore the rest...
// parent page mock up, randomly return a parentPageId that equates to false
function getParentPage(pageId) {
return { id: 1, slug: "slug", title: "title", parentPageId: Math.floor(Math.random() * 2) };
}
console.log(getBreadcrumb(3));
This can be done easier iteratively
var fillArray = function(num, len) {
var result = [];
for (var i = 0; i < len; i++) {
result.push(num);
}
return result;
}
If you really must use recursion this should work
var fillArray = function(num, len) {
if (len === 0) {
return [];
}
return [num].concat(fillArray(num, len - 1));
}
You can do it like this, but it's not very efficient to be honest.
function arrayFill(num, length){
if(length === 0) return [];
return [].concat(num, arrayFill(num, length - 1));
}
console.log(arrayFill(5, 3));
The key to building up an array with recursion is the concat() method, which will properly return a copy of the array all the way up the recursion stack.
In the example below, objects that match your criteria get added in with push(), while child objects are searched through recursively and their results are concatenated to the result array. For simplicity I used the results of what your getFolder()function would return in the data:
var structure = {
folder: {id:1, name:'name1'}, //getFolder(1, 'name1'),
children: [{
folder: {id:2, name:'name2'}, //getFolder(2, 'name2'),
children: [{
folder: {id:4, name:'name2'}, //getFolder(4, 'name2'),
children: []
}]
}, {
folder: {id:3, name:'name3'}, //getFolder(3, 'name3'),
children: []
}]
};
function searchAll(object, criteria) {
var i, j, result = [];
for (i in object) {
if (i === criteria.type && object[i][criteria.index] === criteria.value) {
result.push(object);
} else if (i === 'children' && object[i].length > 0) {
for (j = 0; j < object[i].length; j++) {
result = result.concat(searchAll(object[i][j], criteria));
}
}
}
return result;
}
console.log(searchAll(structure, {type: 'folder', index: 'name', value: 'name2'}));
Edit: link to JSFiddle because it looks like the SO code snippet stops the recursion, the results should be correct (2 objects with the data you wanted) https://jsfiddle.net/fswmxk7h/
The main issue is that you are bailing out and not appending to results when you find a match (return data;). This is a hopefully simpler and working version. You also have a problem that you are both passing 'results' to the recursion, and pushing the resulting array onto results, which isn't what you wanted. This is hopefully correct for the style you are going for (untested):
var searchAll = function (data, searchFor, results) {
results = results || [];
if (data[searchFor.type] &&
data[searchFor.type][searchFor.index].indexOf(searchFor.value) !== -1) {
results.push(data); // now carry on an recurse children
}
if (data.children) {
for (var i = 0; i < data.children.length; i++) {
// use results arg to avoid array creation on recursion:
searchAll(data.children[i], searchFor, results);
}
}
return results;
};
searchAll(structure, {
type: 'folder',
index: 'name',
value: 'name2'
});