Javascript 从嵌套对象树获取路径

Javascript 从嵌套对象树获取路径,javascript,recursion,coffeescript,Javascript,Recursion,Coffeescript,我现在遇到了一个问题,刚开始的时候似乎不难解决,但现在我遇到了几个小时,所以我们开始: 给定此对象数组: groups = [ { name: 'Custard apple', slug: 'custard-apple', children: [ { name: 'Vanilla', slug: 'vanilla', children: [ { name: 'Str

我现在遇到了一个问题,刚开始的时候似乎不难解决,但现在我遇到了几个小时,所以我们开始:

给定此对象数组:

groups = [
  {
    name: 'Custard apple',
    slug: 'custard-apple',
    children: [
      {
        name: 'Vanilla',
        slug: 'vanilla',
        children: [
          {
            name: 'Strawberry',
            slug: 'strawberry',
            children: []
          }, {
            name: 'Pineapple',
            slug: 'pineapple',
            children: []
          }
        ]
      }, {
        name: 'Chocolate',
        slug: 'chocolate',
        children: []
      }
    ]
  }, {
    name: 'Raspberry',
    slug: 'raspberry',
    children: []
  }, {
    name: 'Lemon',
    slug: 'lemon',
    children: [
      {
        name: 'Orange',
        slug: 'orange',
        children: [
          {
            name: 'Coconut',
            slug: 'coconut',
            children: []
          }
        ]
      }, {
        name: 'Almond',
        slug: 'almond',
        children: []
      }
    ]
  }
];
我试图找到一个函数,该函数通过一个给定的
slug
为我提供一个对象的路径:

var find_path = function(groups, slug) { /* looking for a solution to this */ };
result = find_path(groups, 'pineapple'); 

console.log(result);
// [{ name: 'Custard Apple', slug: 'custard-apple' }, { name: 'Vanilla', slug: 'vanilla'}, { name: 'Pineapple', slug: 'pinapple' }]

// another example
result = find_path(groups, 'lemon');
console.log(result);
// [{ name: 'Lemon', slug: 'lemon' }]
我尝试了几种递归方法,在这些方法中,我试图沿函数调用保存路径,但通常结果都是重复的/通常不是期望的结果。我主要围绕递归查找和(失败的)保存路径的尝试展开讨论


那么,有没有递归的方法来解决这个问题呢?还是我的想法太复杂了

您处理的是一棵树,因此递归是一种自然的解决方案。简单的深度优先搜索(查看当前节点,然后查看其子节点)可能是最简单的解决方案。大概是这样的:

slice = (o, properties...) ->
    ret = { }
    ret[p] = o[p] for p in properties
    ret

find_path = (a, slug) ->
    for o in a
        # Bail out now if this is what we're looking for.
        if(o.slug == slug)
            return [ slice(o, 'name', 'slug') ]
        # Scan the children if not.
        if(sub = find_path(o.children, slug))
            return [ slice(o, 'name', 'slug') ].concat(sub)
    # Explicitly return `undefined` to make sure the caller
    # gets The Right Thing back.
    return
演示:

递归中的每一步都不提供任何内容,也不提供从当前节点到要查找节点的路径。然后,展开递归构建通过调用的路径。诚然,这里有相当多的数组复制,但对于这样的小数据集,不值得担心(如果您有更多数据,那么您可能希望切换到某种索引结构)


slice
函数只是为了让“copy
e
而不是
e.children
”逻辑更具可读性;不幸的是,你不能在一个数组中使用像
{x.a,x.b}=obj
这样的复合结构,所以
切片
函数就和你要得到的一样好(你可以说
{a,b}=obj
,但是你不能添加额外的嵌套级别来得到一个对象切片)。

你正在处理一个树,所以递归是一个自然的解决方案。简单的深度优先搜索(查看当前节点,然后查看其子节点)可能是最简单的解决方案。大概是这样的:

slice = (o, properties...) ->
    ret = { }
    ret[p] = o[p] for p in properties
    ret

find_path = (a, slug) ->
    for o in a
        # Bail out now if this is what we're looking for.
        if(o.slug == slug)
            return [ slice(o, 'name', 'slug') ]
        # Scan the children if not.
        if(sub = find_path(o.children, slug))
            return [ slice(o, 'name', 'slug') ].concat(sub)
    # Explicitly return `undefined` to make sure the caller
    # gets The Right Thing back.
    return
演示:

递归中的每一步都不提供任何内容,也不提供从当前节点到要查找节点的路径。然后,展开递归构建通过调用的路径。诚然,这里有相当多的数组复制,但对于这样的小数据集,不值得担心(如果您有更多数据,那么您可能希望切换到某种索引结构)

slice
函数只是为了让“copy
e
而不是
e.children
”逻辑更具可读性;不幸的是,你不能在一个应用程序中使用像
{x.a,x.b}=obj
这样的复合结构,所以
切片
函数就和你要得到的一样好(你可以说
{a,b}=obj
,但是你不能添加额外的嵌套级别来获得对象切片)。

谢谢:)回想起来,这对我来说应该更明显。谢谢:)回想起来,这对我来说应该更明显。