【问题标题】:Find path in tree by direct path通过直接路径在树中查找路径
【发布时间】:2019-08-28 06:52:06
【问题描述】:

我有类似的问题:JavaScript: Find all parents for element in tree recursive

但我找不到name 的路径,而是direct path

const path = ["name1", "name4", "name5"];

const data = [
    {
        'name': 'name1',
        'tree': [
            {'name': 'name2'},
            {'name': 'name3'},
            {
                'name': 'name4',
                'tree': [
                    {'name': 'name5'},
                    {'name': 'name6'}
                ]
            },
            {'name': 'name7'}
        ]
    },
    {
        'name': 'name8',
        'tree': [
            {'name': 'name9'}
        ]
    }
];

它返回所有可能的路径或什么都不返回。

path 太短时,它什么也不返回。

path 太长时,它什么也不返回。

感谢您的帮助!

所需输出示例:

const path = ["name1", "name4", "name5"];
findAPath(data, path) 

返回:["name1", "name4", "name5"]

const path = ["name1", "name7", "name5"];
findAPath(data, path)

返回[]

const path = ["name1", "name4", "name5", "name5"];
findAPath(data, path) 

返回[]

我的尝试:

let index = 0;
function find(data, index) {
    let index = index;
    data.some((o) => {
        if(o.name == path[index]) {
            index++;
            find(o.tree, index);
        }
    });
    // I don't know what return here.
    // I need to probably return path where I am.
    return <>;
}

【问题讨论】:

  • 你能举个例子吗? path = ["name1", "name4", "name5"] 应该返回什么?另外,最重要的是,你有没有尝试过?
  • 已编辑。我尝试了一些递归函数,但没有成功。我尝试过的任何方式都让我大吃一惊。
  • 好的,不管成功与否,StackOverflow 上都希望你展示你的尝试,这样人们就可以调试并帮助你如何达到预期的结果,否则看起来你想让我们编码给你
  • 已编辑。对不起。我的尝试不是什么大事,对我来说似乎并不重要。

标签: javascript recursion tree


【解决方案1】:

使用Array.prototype.flatMap

这是一个使用mutual recursion 技术的功能解决方案 -

const None =
  Symbol ()

const findPath = (tree = [], names = [], r = []) =>
  tree.length && names.length                              // base: and
    ? tree.flatMap(branch => findPath1(branch, names, r))
    : tree.length || names.length                          // inductive: xor
        ? []
        : [ r ]                                            // inductive: nor                                     // inductive: nor

const findPath1 = ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = []) =>
  name === "" && q === None                    // base: and
    ? [ r ]
    : name === "" || q === None || name !== q  // inductive: xor
        ? []
        : findPath(tree, more, [ ...r, q ])    // inductive: nor

findPath(data, ["name1", "name4", "name5"])
// => [ [ "name1", "name4", "name5" ] ]

注意,如果您的数据包含 多个 到输入值的路径,则将返回 所有 路径 -

const data = [
  {
      'name': 'name1',                   // name1
      'tree': [
          {'name': 'name2'},
          {'name': 'name3'},
          {
              'name': 'name4',           // name1->name4
              'tree': [
                  {'name': 'name5'},     // name1->name4->name5
                  {'name': 'name6'}
              ]
          },
          {
            'name': 'name4',             // name1->name4
            'tree': [
                {'name': 'name5'},       // name1->name4->name5
                {'name': 'name6'}
              ]
          },
          {'name': 'name7'}
      ]
  },
  {
      'name': 'name8',
      'tree': [
          {'name': 'name9'}
      ]
  }
]

就像你问的那样,它返回所有可能的路径,或者什么都不返回 -

findPath(data, ["name1", "name4", "name5"])
// => [ [ "name1", "name4", "name5" ],
//      [ "name1", "name4", "name5" ] ]

findPath(data, [ "name1", "name7" ])
// => [ [ "name1", "name7" ] ]

findPath(data, [ "name1", "name9" ])
// => []

当路径太短或太长时,它不会返回任何东西-

findPath(data, [ "name1", "name4" ])
// => []

findPath(data, [ "name1", "name4", "name5", "name6" ])
// => []

展开下面的sn-p,在自己的浏览器中验证结果-

const None =
  Symbol ()

const findPath = (tree = [], names = [], r = []) =>
  tree.length && names.length
    ? tree.flatMap(branch => findPath1(branch, names, r))
    : tree.length || names.length
        ? []
        : [ r ]

const findPath1 = ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = []) =>
  name === "" && q === None
    ? [ r ]
    : name === "" || q === None || name !== q
        ? []
        : findPath(tree, more, [ ...r, q ])

const data = [
  {
      'name': 'name1',
      'tree': [
          {'name': 'name2'},
          {'name': 'name3'},
          {
              'name': 'name4',
              'tree': [
                  {'name': 'name5'},
                  {'name': 'name6'}
              ]
          },
          {'name': 'name7'}
      ]
  },
  {
      'name': 'name8',
      'tree': [
          {'name': 'name9'}
      ]
  }
]

console.log(findPath(data, ["name1", "name4", "name5"]))
// [ [ "name1", "name4", "name5" ] ]

console.log(findPath(data, [ "name1", "name7" ]))
// [ [ "name1", "name7" ] ]

console.log(findPath(data, [ "name1", "name9" ]))
// []

使用生成器

这是使用生成器的替代实现 -

const None =
  Symbol ()

const findPath = function* (tree = [], names = [], r = [])
{ if (tree.length && names.length)        // base: and
    for (const branch of tree)
      yield* findPath1(branch, names, r)
  else if (tree.length || names.length)   // inductive: xor
    return
  else                                    // inductive: nor
    yield r
}

const findPath1 = function* ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = [])
{ if (name === "" && q === None)                     // base: and
    yield r
  else if (name === "" || q === None || name !== q)  // inductive: xor
    return
  else                                               // inductive: nor
    yield* findPath(tree, more, [ ...r, q ])
}

它的输出与上面完全相同,只是将可迭代生成器强制转换为数组,我们使用Array.from -

Array.from(findPath(data, ["name1", "name4", "name5"]))
// => [ [ "name1", "name4", "name5" ] ]

Array.from(findPath(data, [ "name1", "name7" ]))
// => [ [ "name1", "name7" ] ]

Array.from(findPath(data, [ "name1", "name9" ]))
// => []

展开下面的sn-p,在自己的浏览器中验证结果-

const None =
  Symbol ()

const findPath = function* (tree = [], names = [], r = [])
{ if (tree.length && names.length)
    for (const branch of tree)
      yield* findPath1(branch, names, r)
  else if (tree.length || names.length)
    return
  else
    yield r
}

const findPath1 = function* ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = [])
{ if (name === "" && q === None)
    yield r
  else if (name === "" || q === None || name !== q)
    return
  else
    yield* findPath(tree, more, [ ...r, q ])
}

const data = [
  {
      'name': 'name1',
      'tree': [
          {'name': 'name2'},
          {'name': 'name3'},
          {
              'name': 'name4',
              'tree': [
                  {'name': 'name5'},
                  {'name': 'name6'}
              ]
          },
          {'name': 'name7'}
      ]
  },
  {
      'name': 'name8',
      'tree': [
          {'name': 'name9'}
      ]
  }
]

console.log(Array.from(findPath(data, ["name1", "name4", "name5"])))
// [ [ "name1", "name4", "name5" ] ]

console.log(Array.from(findPath(data, [ "name1", "name7" ])))
// [ [ "name1", "name7" ] ]

console.log(Array.from(findPath(data, [ "name1", "name9" ])))
// []

它们是如何相同的;他们怎么不

注意两个实现之间的相似性以及结果是如何形成的。两者都使用相互递归。函数式解决方案使用表达式,而生成器解决方案使用语句。生成器实现扩展了一个明显的优势,我们可以随时选择停止或继续迭代(“查找”)。

例如,想象一个输入,其中给定输入有十 (10) 个唯一路径。也许我们只想返回第一个匹配项,

const findFirst = (tree = [], names = []) =>
{ for (const path of findPath(tree, names))
    return path
}

或者获得前三 (3) 场比赛 -

const findFirst3 = (tree = [], names = []) =>
{ const r = []
  for (const path of findPath(tree, names))
    if (r.length < 3)
      r.push(path)
  return r
}

或者获取第一个N-

const findFirstN = (tree = [], names = [], n = 0) =>
{ const r = []
  for (const path of findPath(tree, names))
    if (r.length < n)
      r.push(path)
  return r
}

发电机像这样灵活。相比之下,flatMap 实现是急切的,总是返回所有结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    相关资源
    最近更新 更多