javascript - Recursive function prints correct final result inside the loop but then is undefined outside - Stack Overflow

I need another set of eyes. There has to be something small I'm just missing here. I'm inputt

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 acplished 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'
  )
);

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 acplished 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'
  )
);

Share edited Feb 5, 2020 at 20:05 Robbie Milejczak 5,7903 gold badges35 silver badges68 bronze badges asked Feb 5, 2020 at 20:03 ramram 6905 silver badges17 bronze badges 2
  • 1 In your if branch, there's no return statement. – Bergi Commented Feb 5, 2020 at 20:13
  • Is there a reason you're using recursion instead of reduce()? – redOctober13 Commented Feb 5, 2020 at 20:36
Add a ment  | 

5 Answers 5

Reset to default 5

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 returned 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'
  )
);

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'
  )
);```

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:

  1. Define the recursive fucntion outside 'limit()' function.

  2. Make sure the recursive function always returns a value (array size == 0 and otherwise).

  3. Remove semi-colons and add parentheses to make it easy to spot errors. (Javascript does not need semi-colons at the end of line)

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'
  )
);

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 bining 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...')

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744913588a4600698.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信