javascript - JS 递归映射对象名称

标签 javascript vue.js recursion

我有一个对象数组,其深度未定义。 现在我希望名称输出如下:

Top Level
Top Level > Sub 1
Top Level > Sub 1 > Sub 1-2
Top Level > Sub 2

但是,我总是只得到最低的元素。我不知道我还可以更改什么来使名称格式正确。

        parseCategories(categories, stackCounter = 0) {
          categories.forEach(c => {
            this.res[stackCounter] = { name: c.attributes.name, id: c.id };
            if(c.children.length >= 1) {
              this.parseCategories(c.children, stackCounter + 1);
            }
          });
          return this.res;
        }

我的对象如下所示:

{
   "data":[
      {
         "type":"categories",
         "id":"1",
         "attributes":{
            "name":"Top Level"
         },
         "children":[
            {
               "type":"categories",
               "id":"2",
               "attributes":{
                  "name":"Sub 1"
               },
               "children":[
                  {
                     "type":"categories",
                     "id":"4",
                     "attributes":{
                        "name":"Sub 1-2"
                     },
                     "children":[

                     ]
                  }
               ]
            },
            {
               "type":"categories",
               "id":"3",
               "attributes":{
                  "name":"Sub 2"
               },
               "children":[

               ]
            }
         ]
      }
   ]
}

最佳答案

生成器函数通常会简化此类遍历。在这里,我们可以编写一个非常简单的生成器,然后将其包装在一个函数中,该函数从该生成器创建一个数组:

const getPaths = function * (xs, ps = []) {
  for (let x of xs) {
    yield [... ps, x .attributes .name] .join (' > ')
    yield * getPaths (x .children, [...ps, x .attributes .name])
  }
}

const categoryNames = (categories) => 
  [... getPaths (categories .data)]

const categories = {data: [{type: "categories", id: "1", attributes: {name: "Top Level"}, children: [{type: "categories", id: "2", attributes: {name: "Sub 1"}, children: [{type: "categories", id: "4", attributes: {name: "Sub 1-2"}, children: []}]}, {type: "categories", id: "3", attributes: {name: "Sub 2"}, children: []}]}]};

console .log (
  categoryNames(categories)
)

通过删除 join (' > ') 调用并将其添加到 map 调用中,

getPaths 可能会变得更加通用一些categoryNames 的末尾。但由于 childrenattributes.names 已经相当特定于问题,我可能不会打扰。

<小时/>

说明

您说过您没有完全遵循此代码。这是对其进行解释的尝试。如果我解释一些你已经理解的东西,请不要生气。我不清楚到底需要解释什么。

外部函数categoryNamesgetPaths 的一个非常小的包装器。所有工作都由那个人完成。

关于 getPaths 有两个重要功能需要注意:

  • 这是一个generator function ,由 function 关键字和参数列表之间的 * 表示。生成器函数创建 Generator对象,因为它们符合[可迭代协议(protocol)],所以可以在 let x of Generator[...generator] 等构造中使用。这就是 categoryNamesgetPaths 的输出转换为数组的方式。 (顺便说一句,可迭代协议(protocol)也是 getPaths 中的 for-of 循环将数组转换为值序列的方式。)生成器函数通过 yield 工作。 code>ing 单个值或使用 yield * anotherGenerator 单独生成另一个生成器生成的每个值。在这些 yield 调用之间,函数会暂停,直到请求下一个值。

  • 这是一个recursive function ;函数体使用更简单的参数再次调用同一函数。大多数情况下,在递归函数中,您会看到显式的基本情况,当输入足够简单时,直接返回答案而无需递归调用。这里的基本情况是隐含的。当xs为空数组时,for循环的主体永远不会被调用,因此递归结束。

getPaths 接受值数组(xs 是我对未知类型值列表的默认名称;nodes 也可以是一个好名字),它接受一个字符串数组,表示层次结构中直到当前节点的路径。因此,它可能包含 ["Top Level", "Sub 1"]。请注意,这是 default parameter ;如果你不提供它,它将被给予一个空数组。

我们循环提供给我们的值。对于每一个,我们首先通过散布 "> "< 来生成当前路径和当前对象的 attribute 属性的 name 属性组合的结果 他们之间。然后,我们通过传递子项和一组名称(包括当前名称)来递归,依次生成其每个子项。这个版本可能性能稍好一些,而且更容易阅读:

const getPaths = function * (xs, paths = []) {
  for (let x of xs) {
    const newPaths = [... paths, x .attributes .name]
    yield newPaths .join (' > ')
    yield * getPaths (x .children, newPaths)
  }
}

如果您愿意,您可以像这样定义newPaths:

    const newPaths = paths .concat (node .attributes .name)

我希望这会有所帮助。如果您对此有疑问,请添加评论。

关于javascript - JS 递归映射对象名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58871956/

相关文章:

javascript - 如何将ID添加到jquery插件选择器中

vue.js - 我如何在vue js中的一页路由下显示不同的category._id

javascript - Vuejs 输入绑定(bind)与计算属性中的附加属性

javascript - Ajax 请求未提供任何数据

haskell - Haskell中的整数平方根函数

javascript - 递归遍历一个json对象 Results in "uncaught syntaxError: Illegal return statement"

javascript - 基于ie浏览器版本的网站重定向

javascript - 如何获得关于 on click 语句的 return 和 end 的正确引用?

javascript - 如何在javascript中检查null?

c++ - 为什么这个递归函数只有在使用 ELSE 时才有效