找到对象的路径,在该对象的对象数组中有一个具有特定功能的键

时间:2019-05-13 08:31:06

标签: javascript algorithm vue.js

比方说,我有如下的字典数组。如何使用id: 121查找到对象的路径。我正在尝试用javascript做到这一点,但与此无关。我需要一种算法或某种方法来实现这一目标。

我期望的结果类似于[{id:1, name:"foo"}, {id: 12, name:"shoo"}, {id: 121, name:"jhj"}]

[
    {
        "id": 1,
        "name": "foo",
        "submenus": [
            {
                "id": 11,
                "name": "bar",
                "submenus": [
                    {
                        "id": 111,
                        "name": "abc"
                    }
                ]
            },
            {
                "id": 12,
                "name": "shoo",
                "submenus": [
                    {
                        "id": 121,
                        "name": "jhj"
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "name": "kjk"
    }
]

这是我为此编写的代码。该代码用于VueJS。

getBreadcrumbs(menuItems, id, breadcrumpsArray) {
    for (var i = 0; i < menuItems.length; i++) {
      if (menuItems[i].id == id) {
        breadcrumpsArray.push({
          id: menuItems[i].id,
          name: menuItems[i].text
        })
        return breadcrumpsArray
      } else {
        if (menuItems[i].submenus !== 'undefined') {
          if (menuItems[i].submenus.length > 0) {
            console.log('shoo')
            this.getBreadcrumbs(menuItems[i].submenus, id, breadcrumpsArray)
          }
        }
      }
    }
  }

这显示错误信息:

Error in render: "TypeError: menuItems[i].submenus is undefined"

3 个答案:

答案 0 :(得分:2)

您可以定义一个递归函数findPath()来实现所需的功能。请参阅下面的片段中记录的注释:

const data=[{"id":1,"name":"foo","submenus":[{"id":11,"name":"bar","submenus":[{"id":111,"name":"abc"}]},{"id":12,"name":"shoo","submenus":[{"id":121,"name":"jhj"}]}]},{"id":2,"name":"kjk"}];

/* Define a recursive function that finds the item path from root
of the data set, to the first child found with matching id */
const findPath = (items, id) => {
    
    /* Iterate the items of this level */
    for(const item of items) {

        if(item.id === id) {
            /* If id matches id, return tail of resulting array that 
            will be our path result */
            return [item]
        }
        else if(Array.isArray(item.submenus)) {
            /* If submenus sub array present, search the items of the
            submenu recursivly for a nested child with matching id */
            const result = findPath(item.submenus, id)
            if(Array.isArray(result)) {
                /* If recursive call returns an array result, this means
                a nested child with id was found, so prefix this item to
                the results array */
                return [item].concat(result)
            }
        }
    }
}

/* Map id and name of each item in found path to result array */
const result = findPath(data, 121).map(({ id, name }) => ({ id, name }));

console.log( result );

另外,作为单独的注释,在您当前的代码中,这是检查菜单项上submenus子数组是否存在的一个小错误。

应用以下更改应导致您看到的错误:

getBreadcrumbs(menuItems, id, breadcrumpsArray) {
    for (var i = 0; i < menuItems.length; i++) {
        if (menuItems[i].id == id) {

            breadcrumpsArray.push({
                id: menuItems[i].id,
                name: menuItems[i].text
            });

        } else {

            /* Add "typeof" here to determine if submenus if undefined in this way */
            if (typeof menuItems[i].submenus !== 'undefined') {
                if (menuItems[i].submenus.length > 0) {
                    this.getBreadcrumbs(menuItems[i].submenus, id, breadcrumpsArray)
                }
            }
        }
    }

    /* Move this here */
    return breadcrumpsArray;
}

有关此typeof运算符see this documentation

的更多信息,

答案 1 :(得分:1)

您可以找到路径,如果找到该路径,则将节点的对象带入结果集中。

function findPath(array, target) {
    var path;
    return array.some(({ id, name, submenus = [] }) => {
            if (id === target) return path = [{ id, name }];
            var temp = findPath(submenus, target);
            if (temp.length) return path = [{ id, name }, ...temp];
        })
        ? path
        : [];
}

var array = [{ id: 1, name: "foo", submenus: [{ id: 11, name: "bar", submenus: [{ id: 111, name: "abc" }] }, { id: 12, name: "shoo", submenus: [{ id: 121, name: "jhj" }] }] }, { id: 2, name: "kjk" }];;

console.log(findPath(array, 121))
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:1)

我终于找到了一种方法,这是我算法的步骤:

  • 首先,DFS (Depth First Search)您的树,直到找到您要查找的id的节点

  • 找到它后,将其推到breadscrumpArray并返回breadscrumpArray

  • 每次我们搜索submenu元素时,我们都会知道我们要查找的节点是否是该元素的子元素,就像它不是子元素一样,函数{{ 1}}将是getBreadcrumbs

希望能有所帮助,如果您有任何疑问,请告诉我,加油!

false