如何检查嵌套对象是否是不使用jQuery的另一个对象的后代

时间:2017-10-17 22:19:37

标签: javascript lodash

我有以下对象。我想要做的是提出一个函数,该函数将指定给定对象是否是id的父元素的后代。例如,我想这样做:欢迎lodash。

isThisDescendant(7,1) //true
isThisDescendant(1,7) //false
isThisDescendant(7,3) //false
isThisDescendant(3,2) //true

object = {
    children : [
        {
            name: 'a',
            id: 1,
            children: [
                {
                    name: 'b',
                    id: 2,
                    children: [
                        {
                            name: 'c',
                            id: 3,
                            children: []
                        },
                        {
                            name: 'cc',
                            id: 4,
                            children: []
                        }                       
                    ]
                },
                {
                    name: 'ba',
                    id: 6,
                    children: [
                        {
                            name: 'c',
                            id: 8,
                            children: []
                        },
                        {
                            name: 'cd',
                            id: 7,
                            children: []
                        }                       
                    ]
                }               
            ]
        },
        {
            name: 'bb',
            id: 10,
            children: []
        }
    ]
}

5 个答案:

答案 0 :(得分:1)

可能有点过于冗长,但有一些输入参数可以像这样做



function findNodeById( branch, id ) {
  if (!branch) {
    return null;
  }
  if (branch.id === id) {
    return branch;
  }
  for (let child of branch.children) {
    let result = findNodeById( child, id );
    if (result) {
      return result;
    }
  }
  return null;
}

function isThisDescendant(tree, childId, parentId ) {
  const parent = findNodeById( tree, parentId );
  if (!parent) {
    return false;
  }
  const child = findNodeById( parent, childId );
  return child !== null;
}

const branch = {
    children : [
        {
            name: 'a',
            id: 1,
            children: [
                {
                    name: 'b',
                    id: 2,
                    children: [
                        {
                            name: 'c',
                            id: 3,
                            children: []
                        },
                        {
                            name: 'cc',
                            id: 4,
                            children: []
                        }                       
                    ]
                },
                {
                    name: 'ba',
                    id: 6,
                    children: [
                        {
                            name: 'c',
                            id: 8,
                            children: []
                        },
                        {
                            name: 'cd',
                            id: 7,
                            children: []
                        }                       
                    ]
                }               
            ]
        },
        {
            name: 'bb',
            id: 10,
            children: []
        }
    ]
};
console.log(isThisDescendant(branch, 7,1)); //true
console.log(isThisDescendant(branch, 1,7)) //false
console.log(isThisDescendant(branch, 7,3)) //false
console.log(isThisDescendant(branch, 3,2)) //true




答案 1 :(得分:1)

您可以创建将在数组上使用forEach循环的递归函数,并检查在任何级别上看到第二个参数后是否存在第一个参数。

var object = {"children":[{"name":"a","id":1,"children":[{"name":"b","id":2,"children":[{"name":"c","id":3,"children":[]},{"name":"cc","id":4,"children":[]}]},{"name":"ba","id":6,"children":[{"name":"c","id":8,"children":[]},{"name":"cd","id":7,"children":[]}]}]},{"name":"bb","id":3,"children":[]}]}


function isThisDescendant(a, b) {
  var r = false;

  function f(a, b, data = object, p = false) {
    if (Array.isArray(data)) {
      data.forEach(function(o) {
        if (p && a == o.id) r = true;
        else f(a, b, o.children, !p ? b == o.id : p)
      })
    } else f(a, b, data.children, p)
  }
  f(a, b)
  return r
}

console.log(isThisDescendant(7, 1)) //true
console.log(isThisDescendant(1, 7)) //false
console.log(isThisDescendant(7, 3)) //false
console.log(isThisDescendant(3, 2)) //true

答案 2 :(得分:0)

有许多解决方案,但为了提高效率,需要采取某些假设:

  1. 这是一次性事情还是需要不断查询?

    如果是一次性操作,那么您可以通过简单的广度优先搜索来寻找父级,然后检查其子级是否包含您正在寻找的id。这是O(n)。

    如果不是,那么您应该构建一个查找表(id, instance),然后使用该表查找您的父项并进行检查。这或多或少是O(1)到O(log n),因为子尺寸小于整个尺寸的尺寸。

  2. children数组是否已排序?

    如果对数组进行了排序,一旦拥有父实例,就可以对children数组执行二进制搜索,以进一步优化它。

答案 3 :(得分:0)

这里需要执行两个步骤 - 抓取树以找到“容器”,然后从容器中向下爬行以找到后代。

const object = {
    children : [
        {
            name: 'a',
            id: 1,
            children: [
                {
                    name: 'b',
                    id: 2,
                    children: [
                        {
                            name: 'c',
                            id: 3,
                            children: []
                        },
                        {
                            name: 'cc',
                            id: 4,
                            children: []
                        }                       
                    ]
                },
                {
                    name: 'ba',
                    id: 6,
                    children: [
                        {
                            name: 'c',
                            id: 8,
                            children: []
                        },
                        {
                            name: 'cd',
                            id: 7,
                            children: []
                        }                       
                    ]
                }               
            ]
        },
        {
            name: 'bb',
            id: 10,
            children: []
        }
    ]
}

function isThisDescendant( descendentId, containerId, root = object, foundContainer = false ) {
   if ( root.id === descendentId && foundContainer ) return true; //found it inside the container
   if ( root.id === descendentId && !foundContainer ) return false; //we found the descendent before the container

   //recurse down to children
   const newFoundContainer = foundContainer || root.id === containerId;
   const childResults = root.children.map( 
      child => isThisDescendant( descendentId, containerId, child, newFoundContainer )
   );
   return or( childResults );  //return true if any of the children hits
}

//returns true if any items in the array are true
function or( values ) {
   return Boolean( values.filter( Boolean ).length );
}

    
console.log( isThisDescendant(7,1) ); //true
console.log( isThisDescendant(1,7) ); //false
console.log( isThisDescendant(7,3) ); //false
console.log( isThisDescendant(3,2) );//true

一些注意事项:

  • 大树上的性能非常差 - 使用索引加速(如果每个对象都知道它的父级,你可以更容易地走上树)。
  • 我们使用默认参数值,以便第一次调用递归函数始终从顶部(root = object)开始,foundContainer变量始于false,因此我们寻找容器第一
  • 因为这会分支出来,所以我避免将foundContainer存储为持久状态 - 最好每次都记下要传递的内容并保持递归“纯粹”(没有状态/副作用)

答案 4 :(得分:0)

这个问题涉及一个常见问题:在树中找到一个“喜欢”结构的节点。这总是涉及递归。

您可以编写一个函数isDescendant(rootObj, valueA, valueB)。它看起来像这样:

function isDescendant(rootObj, parentId, childId) {
  const parentNode = findChildren(rootObj, parentId); // Find the parent node
  if (!parentNode) return false;
  return !!findChildren(parentNode, childId); // Find the child node
}

function findChildren(obj, id) {
  if (obj.id === id) return obj;
  if (obj.children) return obj.children.find(c => findChildren(c, id));
}