简体   繁体   中英

Why is my recursive function not returning the last element in the array?

so i was going through the course of FreeCodecamp and stumbled upon this task which I solved with a for-loop. But to test my knowledge about recursive function I wanted to give it a try. But for some reason the array at the end only contains the third and second element.

Code:

Task from:
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/es6/create-strings-using-template-literals

const result = {
    success: ["max-length", "no-amd", "prefer-arrow-functions"],
    failure: ["no-var", "var-on-top", "linebreak"],
    skipped: ["no-extra-semi", "no-dup-keys"]
  };

  const failureItems = [];

  function makeList(arr) {
    // Only change code below this line
  
    // for (let i = 0; i < arr.length; i++)
    // {
    //   failureItems.push(`<li class="text-warning">${arr[i]}</li>`);
    // }  
    
    if(arr.length === 1){
      return arr[0];
    } else {
      failureItems.push(`<li class="text-warning">${arr.pop()}</li>`);
      if(arr.length >= 1){
        makeList(arr);}
    }
    console.log("Log before return:" + failureItems[0]);  
    // Only change code above this line
    return failureItems;
  }
  const failuresList = makeList(result.failure);
  console.log(`Failure list is ${failuresList}`);

I added console.log where I thought the problem occurs but I just cant pinpoint the line that gives me trouble.

you are not pushing first element ever.

although recursion might not be the best solution the way you are doing it.. but you can recurse till array is empty

if(arr.length === 0){
      return;
    } else {
      failureItems.push(`<li class="text-warning">${arr.pop()}</li>`);
      if(arr.length >= 1){
        makeList(arr);}
    }

Your code is mostly correct, and the only reason why it doesn't give each output is the base condition ie where the recursion should end at.

The only base condition that is appropriate for pushing elements here is till the array is empty. This allows you to actually push the first element as well.

The revised code is as follows:

const result = {
    success: ["max-length", "no-amd", "prefer-arrow-functions"],
    failure: ["no-var", "var-on-top", "linebreak"],
    skipped: ["no-extra-semi", "no-dup-keys"]
  };

  const failureItems = [];

  function makeList(arr) {
    
    // your base condition

    if(arr.length === 0){
      return;
    } else {
      failureItems.push(`<li class="text-warning">${arr.pop()}</li>`);
    }
    if(arr.length >= 1){
        makeList(arr);}
    console.log("Log before return:" + failureItems[0]);  
    
    // Only change code above this line
    return failureItems;
  }
  const failuresList = makeList(result.failure);
  console.log(`Failure list is ${failuresList}`);

The recursive function is called one by one for each element in the array and it is pushed into the list till the array becomes empty ie

arr.length === 0

Kindly upvote if it helped!

You code, even once corrected by the other answers, has two real problems.

First, you're reversing the array as you go. This is a result of repeatedly calling pop , moving from right to left through the input array, and then placing the result at the end of the output array with push , now moving left to right.

Second, and worse, you are mutating the input in an unrecoverable manner. By calling pop , you are destroying your result object. If you log it when you're done, you'll see that result.failure is now an empty array. Uggh!

A simple way to get around these problems is to use Array.prototype.map to convert an array of values into another one by applying the same function to each value:

 const makeList = (arr) => arr.map (reason => `<li class="text-warning">${reason}</li>`) const result = { success: ["max-length", "no-amd", "prefer-arrow-functions"], failure: ["no-var", "var-on-top", "linebreak"], skipped: ["no-extra-semi", "no-dup-keys"] } const failuresList = makeList (result.failure) console.log (`Failure list is ${failuresList}`)

If you really want to do this recursively, you might try something like

const makeList = (reasons) =>
  reasons .length == 0 
    ? []
    : [`<li class="text-warning">${reasons [0]}</li>`, ...makeList (reasons .slice (1))]

Or the slightly more succinct variant I would prefer:

const makeList = ([reason, ...reasons]) => 
  reason == undefined 
    ? [] 
    : [`<li class="text-warning">${reason}</li>`, ...makeList (reasons)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM