Javascript - remove child or parent elements from an array

时间:2018-05-28 18:56:09

标签: javascript

I got a code to remove child/parent elements from a random array that might contain both a child and a parent element, for example:

<html>

    <body>
        <div id='1'>
            <div id='2'>
                <div id='3'>
                </div>
                <div id='4'>
                </div>
            </div>
        </div>
        <div id='5'>
            <div id='6'>
            </div>
        </div>
    </body>

</html>

arr = document.getElementsByTagName('div')
// arr: [<div#1>,<div#2>, <div#3>, <div#4>, <div#5>, <div#6>]

So from this example how can I extract the children:

// arr: [<div#3>, <div#4><div#6>]

Or extract the parents:

// arr: [<div#1>, <div#5>]

currently I'm using:

function isDescendant(parent, child) {
     var node = child.parentNode;
     while (node != null) {
         if (node == parent) {
             return true;
         }
         node = node.parentNode;
     }
     return false;
}

function filterArray(arr, parent=true){
    newArr = [];
    arr.forEach((a)=>{
        bool = true

        if (parent){
            arr.forEach((b)=>{
                if (isDescendant(a, b)){
                    bool = false
                };
            });
        }
        else{
            arr.forEach((b)=>{
                if (isDescendant(b, a)){
                    bool = false
                };
            });            
        }

        if(bool){
            newArr.push(a)
        }
    });
    return newArr
};

But I'm pretty sure there could be a better solution, more efficient. Any idea for a better solution?

3 个答案:

答案 0 :(得分:1)

数组有一个名为filter的方法,可以让你做到这一点;过滤数组。要查找节点是否是另一个节点的父节点或子节点,您可以使用contains - 方法(请注意,在检查节点是否包含自身时,这可能会返回true),或者更通用的{{3} } -method。

<div id='1'>
  <div id='2'>
    <div id='3'>
    </div>
    <div id='4'>
    </div>
  </div>
</div>
<div id='5'>
  <div id='6'>
  </div>
</div>
contains

快速基准测试显示最快的方法(至少在我的机器上)(毫不奇怪,它不必多次搜索数组),然后是compareDocumentPosition - 版本。最慢的是使用filterArray,但这仍然比运行npm install --save-dev babel-plugin-transform-class-properties以获取子数组更快。

答案 1 :(得分:0)

对于儿童可以使用filter()将集合转换为数组querySelector(),当元素不是父母时,它不会返回任何内容

对于外部父母,可以使用Array#some()node#contains()作为过滤器()

&#13;
&#13;
const arr = Array.from(document.querySelectorAll('div'));

const innerChildren = arr.filter(el => !el.querySelector('*')); // or use same selector as master query

const outerParents = arr.filter(e => !arr.some(el => el !== e && el.contains(e)));

console.log(innerChildren) // div#3, div#4 & div#6  
console.log(outerParents) //  div#1, div#5
&#13;
<div id='1'>
  <div id='2'>
    <div id='3'></div>
    <div id='4'></div>
  </div>
</div>
<div id='5'>
  <div id='6'></div>
</div>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

试试以下内容。它选择了正确的答案,虽然不是通用的。希望适用于您的情况。应该在场景下的数据循环较少。

const nodes = Array.from(document.body.querySelectorAll("div"));

const children = nodes.filter( node => 0 === node.querySelectorAll('div').length );
const parents = nodes.filter( node => 'DIV' !== node.parentNode.nodeName );

这是JsFiddle: https://jsfiddle.net/3nhzvat9/

和另一个应该表现得更好的解决方案:

const nodes = document.body.querySelectorAll("div");
const children = [];
const parents = [];

nodes.forEach( node => {
   if(0  === node.querySelectorAll('div').length) {
      children.push(node);
   }
   if('DIV' !== node.parentNode.nodeName){
     parents.push(node);
   }
});

第二个JsFiddle:https://jsfiddle.net/3nhzvat9/1/