基于 id 数组高效循环访问对象



我在移动导航中将用户导航"状态"作为数组获取。例如:

['3124', '5312', '5232']

我需要使用该状态来抓取 ID 为 '5232' 的对象,在对象中向下 3 级。

数组长度可以不同,这意味着它可以返回 1 到 5 个 id,所以我不必总是一直向下循环。

这就是导航数据的样子,使用与我在上面示例中使用的相同的 ID,我希望我的函数返回 ID 为 '5232' 的"晚上"对象:

[
    { 
        id: "3124", 
        name: "women", 
        children: [
            {
                id: "5312",
                name: "dresses",
                children: [
                    {
                        id: "8399",
                        name: "wedding",
                        children: []
                    },
                    {
                        id: "5232",
                        name: "evening",
                        children: []
                    }
                ]
            },
            {
                id: "3291",
                name: "shoes",
                children: []
            }
        ] 
    },
    { 
        id: "9482", 
        name: "men", 
        children: [
            {
                id: "8292",
                name: "jackets",
                children: []
            },
            {
                id: "3829",
                name: "hats",
                children: []
            }
        ] 
    }
]

我一直在和几个同事讨论这个问题,我们真的找不到一个有效的好方法。我们无法更改数据,但如果这是错误的,我们可能可以更改用户状态的保存方式。

我真的可以使用一些关于如何以好的方式解决这个问题的意见和想法。

在树中按路径查找节点的简单函数

function findNodeByPath(nodes, path) {
  let node;
  
  if (!path) return;
  for (let id of path) {
    if (!nodes) break;
    for (let child of nodes) {
      if (child.id === id) {
        node = child;
        nodes = node.children;
        break;
      }
    }  
  }
  return node;
}
let nodes = [
    { 
        id: "3124", 
        name: "women", 
        children: [
            {
                id: "5312",
                name: "dresses",
                children: [
                    {
                        id: "8399",
                        name: "wedding",
                        children: []
                    },
                    {
                        id: "5232",
                        name: "evening",
                        children: []
                    }
                ]
            },
            {
                id: "3291",
                name: "shoes",
                children: []
            }
        ] 
    },
    { 
        id: "9482", 
        name: "men", 
        children: [
            {
                id: "8292",
                name: "jackets",
                children: []
            },
            {
                id: "3829",
                name: "hats",
                children: []
            }
        ] 
    }
];
console.log(findNodeByPath(nodes, ['3124', '5312', '5232']));

您可以迭代数组并仅获取给定路径 id 的节点。

function getObject(tree, path) {
    var temp = { children: tree };
    return path.every(p => temp = temp.children.find(({ id }) => p === id))
        ? temp
        : undefined;
}
var data = [{ id: "3124", name: "women", children: [{ id: "5312", name: "dresses", children: [{ id: "8399", name: "wedding", children: [] }, { id: "5232", name: "evening", children: [] }] }, { id: "3291", name: "shoes", children: [] }] }, { id: "9482", name: "men", children: [{ id: "8292", name: "jackets", children: [] }, { id: "3829", name: "hats", children: [] }] }],
    path = ['3124', '5312', '5232'],
    result = getObject(data, path);
console.log(result);

如果只关注效率,您可以尝试实现基本的嵌套 for 循环。我选择了变量名称breadcrumb因为该概念似乎与它在站点导航中的作用相似。

function getState(breadcrumb, state) {
  let states = state;
  for (let id of breadcrumb) {
    for (state of states) {
      // found -- continue to next level
      if (state.id === id) {
        states = state.children;
        break;
      }
    }
    // not found
    if (state.id !== id) {
      return null;
    }
  }
  return state;
}
let state = [{ id: "3124", name: "women", children: [{ id: "5312", name: "dresses", children: [{ id: "8399", name: "wedding", children: [] }, { id: "5232", name: "evening", children: [] }] }, { id: "3291", name: "shoes", children: [] }] }, { id: "9482", name: "men", children: [{ id: "8292", name: "jackets", children: [] }, { id: "3829", name: "hats", children: [] }] }];
let breadcrumb = ['3124', '5312', '5232'];
console.log(getState(breadcrumb, state));

但是,如果您更关心代码可维护性,我建议您使用更规范的方法:

function getState(breadcrumb, state) {
  return breadcrumb.reduce((state, id) => {
    return state !== null
      ? state.children.find(state => state.id === id)
      : state;
  }, { children: state });
}
let state = [{ id: "3124", name: "women", children: [{ id: "5312", name: "dresses", children: [{ id: "8399", name: "wedding", children: [] }, { id: "5232", name: "evening", children: [] }] }, { id: "3291", name: "shoes", children: [] }] }, { id: "9482", name: "men", children: [{ id: "8292", name: "jackets", children: [] }, { id: "3829", name: "hats", children: [] }] }];
let breadcrumb = ['3124', '5312', '5232'];
console.log(getState(breadcrumb, state));

尝试使用递归函数

   function findById(id) {
      var founded = {};
      function recurse(data){
        for(var i = 0; i < data.length; i++) {
          if (data[i].id === id) {
            founded = data[i];
          } else if (data[i].children && data[i].children.length) {
            recurse(data[i].children);
          }
        }
      }
      recurse(catalog);
      return founded;
    };

一些演示:演示

最新更新