Reputation: 690
I need another set of eyes. There has to be something small I'm just missing here.
I'm inputting a string which is brokend into an array of words, then takes every 5 indexes (words) and joins them into their own index.
This is accomplished through a recursive call.
The final call of the recursion prints the correct result I'm looking for while inside, but the actual returned value outside is undefined..
Please help me out here.
const limit = str => {
const arr = str.split(' ');
function recursiveLimit(arr, acc = []) {
if (arr.length !== 0) {
const toSlice = arr.length < 5 ? arr.length : 5;
const newArr = arr.slice(toSlice);
const newAcc = [...acc, arr.slice(0, toSlice).join(' ')];
recursiveLimit(newArr, newAcc);
} else {
console.log('final array: ', acc); // the array I want to return (looks good here)
return acc; // return it
}
}
return recursiveLimit(arr); // undefined
};
console.log(
'OUTPUT: limit',
limit(
'one two three four five six seven eight nine ten eleven twelve thirteen fourteen'
)
);
Upvotes: 4
Views: 253
Reputation: 50797
As others have pointed out, you're right, it was a simple mistake: you missed an important return
.
It might be cleaner, though, to build this function atop one which chunks an array into multiple parts. Then this code would be responsible only for splitting apart the initial string, calling chunk
, and combining the resulting parts back into strings:
const chunk = (n) => (xs, res = []) =>
xs.length ? chunk (n) (xs .slice (n), [... res, xs .slice (0, n)]) : res
const limit = (str) =>
chunk (5) (str .split (' ')) .map (ss => ss .join (' '))
console .log (
"OUTPUT: limit",
limit ("one two three four five six seven eight nine ten eleven twelve thirteen fourteen")
)
Although chunk
is written in a very different style, it proceeds exactly the same way that your recursiveLimit
does, except that it does not join
the resulting arrays back into strings, leaving that for the function limit
. Note one simplification: Array.prototype.slice
does exactly what you would hope if the limit is out of bounds. For instance, [1, 2, 3] .slice (0, 5) //=> [1, 2, 3]
and [1, 2, 3] .slice (5) //=> []
. So we don't need to capture toSlice
and can just use our chunk length.
limit
is a very simple function now, splitting the input string on " "
into an array of strings, calling chunk (5)
on that array, and mapping
calls to join (" ")
on the resulting array. If we wanted to make it more flexible and replace 5
with a parameter, it would be trivial:
const limit = (n) => (str) =>
chunk (n) (str .split (' ')) .map (ss => ss .join (' '))
limit (5) ('one two three four...')
Upvotes: 2
Reputation: 3974
I'd skip recursion altogether (unless it was a requirement) and just use reduce()
const limit = str => {
const splitBy = 5;
const arr = str.split(' ');
let splitArr = [];
if (arr.length <= 5) return arr;
arr.reduce( (acc, item, idx) => {
if (idx % splitBy === 0) {
//push the block and reset the accumulator
splitArr.push(acc)
acc = item
return acc;
} else if (idx === arr.length-1) {
//the number of items wasn't evenly divisible by the splitter; push out the remainder
splitArr.push(acc + " " + item)
}
else {
//add the current item to the accumulator
return acc+= " " + item;
}
})
return splitArr;
};
console.log(
'OUTPUT: limit',
limit(
'one two three four five six seven eight nine ten eleven twelve thirteen fourteen'
)
);
Upvotes: 2
Reputation: 4937
Here is the fix for the code:
function recursiveLimit(arr, acc = []) {
if (arr.length === 0) {
return acc
}
const toSlice = ((arr.length < 5) ? arr.length : 5)
const newArr = arr.slice(toSlice)
const newAcc = [...acc, arr.slice(0, toSlice).join(' ')]
return recursiveLimit(newArr, newAcc)
}
const limit = (str) => {
return recursiveLimit(str.split(' '))
}
const input = ("one two three four five six seven eight nine ten eleven twelve thirteen fourteen")
console.log("OUTPUT: limit\n", limit(input))
Output:
$ node demo2.js
OUTPUT: limit
[ 'one two three four five',
'six seven eight nine ten',
'eleven twelve thirteen fourteen' ]
Summary of changes made to the code:
I just rearranged the code and made the following subtle changes to reduce the total number of lines and to improve the efficiency:
Define the recursive fucntion outside 'limit()' function.
Make sure the recursive function always returns a value (array size == 0 and otherwise).
Remove semi-colons and add parentheses to make it easy to spot errors. (Javascript does not need semi-colons at the end of line)
Upvotes: 2
Reputation: 111
All you need to do is add a return
before your recursive call of recursiveLimit
on line 8.
Fixed code:
const arr = str.split(' ');
function recursiveLimit(arr, acc = []) {
if (arr.length !== 0) {
const toSlice = arr.length < 5 ? arr.length : 5;
const newArr = arr.slice(toSlice);
const newAcc = [...acc, arr.slice(0, toSlice).join(' ')];
return recursiveLimit(newArr, newAcc);
} else {
console.log('final array: ', acc); // the array I want to return (looks good here)
return acc; // return it
}
}
return recursiveLimit(arr); // undefined
};
console.log(
'OUTPUT: limit',
limit(
'one two three four five six seven eight nine ten eleven twelve thirteen fourteen'
)
);```
Upvotes: 3
Reputation: 5770
To maintain the callstack you should always return recursive function calls. Inside your first if
statement, you don't return a call to your function which leads to an undefined
value. So while acc
moves down the callstack and is properly logged, it doesn't get return
ed back up the callstack and stored in the limit
variable. Simply adding a return
fixes the problem
const limit = str => {
const arr = str.split(' ');
function recursiveLimit(arr, acc = []) {
if (arr.length !== 0) {
const toSlice = arr.length < 5 ? arr.length : 5;
const newArr = arr.slice(toSlice);
const newAcc = [...acc, arr.slice(0, toSlice).join(' ')];
// missing return was here
return recursiveLimit(newArr, newAcc);
} else {
console.log('final array: ', acc);
return acc;
}
}
return recursiveLimit(arr);
};
console.log(
'OUTPUT: limit',
limit(
'one two three four five six seven eight nine ten eleven twelve thirteen fourteen'
)
);
Upvotes: 5