Home > Net >  How to find exact property value using recursion in javascript(typescript)?
How to find exact property value using recursion in javascript(typescript)?

Time:10-07

Let say i have a object response like this

const response = [
    {
        "title": "Menu 1",
        "subMenu": [
            {
                "title": "Menu 1.2"
            }
        ]
    },
    {
        "title": "Menu 2",
    },
    {
        "title": "Menu 3",
        "subMenu": [
            {
                "title": "Menu 3.1",
                "subMenu": [
                    {
                        "title": "Menu 3.2"
                    }
                ]
            }
        ]
    },
    
]

I want to get the object have title "Menu 3.1" using recursion so i wrote this function

const findElement = (arr, title) => {
  for (let index = 0; index < arr.length; index  ) {
    const menu = arr[index];
    if (menu.title === title) {
      return menu;
    } else if (menu.subMenu) {
      return findElement(menu.subMenu, title);
    }
  }
};

and call it like this

console.log(findElement(response, "Menu 3.1" ))

but it log 'undefined'? What did i do wrong?

CodePudding user response:

The issue is, that the code checks response[0], it isn't a match, so checks responsep[0].submenu, but it returns the result of checking that, therefore, the for loop is short-circuited because the target isn't found

What you want to do, when checking sub-menu is check if the there is a result and only return it if there is

A little like this

const response = [{
        "title": "Menu 1",
        "subMenu": [{
                "title": "Menu 1.2"
            }
        ]
    }, {
        "title": "Menu 2",
    }, {
        "title": "Menu 3",
        "subMenu": [{
                "title": "Menu 3.1",
                "subMenu": [{
                        "title": "Menu 3.2"
                    }
                ]
            }
        ]
    },
]

const findElement = (arr, title) => {
    for (let index = 0; index < arr.length; index  ) {
        const menu = arr[index];
        if (menu.title === title) {
            return menu;
        } // no need for else since we return above
        if (menu.subMenu) {
            const sub = findElement(menu.subMenu, title);
            if (sub) return sub;
        }
    }
};

console.log(findElement(response, "Menu 3.1"))

CodePudding user response:

I'd definitely use a reducer here:

const reducer = (result, item) =>
  result ||
  (item.title === "Menu 3.1"
    ? item
    : item.subMenu?.reduce(reducer, null) || null)

console.log(response.reduce(reducer, null))

const response = [
  {
    title: "Menu 1",
    subMenu: [
      {
        title: "Menu 1.2"
      }
    ]
  },
  {
    title: "Menu 2"
  },
  {
    title: "Menu 3",
    subMenu: [
      {
        title: "Menu 3.1",
        subMenu: [
          {
            title: "Menu 3.2"
          }
        ]
      }
    ]
  }
]

const findItemByTitle = (items, title) => {
  const reducer = (a, item) =>
    a ||
    (item.title === title ? item : item.subMenu?.reduce(reducer, null) || null)
  return items.reduce(reducer, null)
}

console.log(findItemByTitle(response, "Menu 3.1"))

I'd argue it's easy to follow:

  • if there's already a result, return it
  • if not, return current item if the title is what we're looking for
  • if not and there's a subMenu return reducer's result on the submenu
  • else return null (which goes to next item)
  • Related