Ruby's Louvre

每天学习一点点算法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

获取祖先元素

在设计选择器时遇到的,当我们使用后代选择器,要从上一次的结果集中获取它们所有后代,可能存在重复元素。虽然排除重复元素是非常简单的事,但我们能不能从一开始就防范其生产重复元素呢?答案是肯定。

假设上一次的结果集有三个元素a,b,c,如果其中两个存在包含关系,即是说A的parentNode或祖先是B,那么一定会出现重复的子集。既然如此,一开始,我们把A去掉,就没问题了。

看下面网页:

<!doctype html>
<html dir="ltr" lang="zh-CN">
  <head>
    <meta charset="utf-8"/>
    <title>排除 重复元素 by 司徒正美</title>
  </head>
  <body id="id10">
    <p id="id1">一<span id="id2">二</span><span id="id3">二</span><span class="bbb">二</span></p>
    <p id="id4">一<span id="id5">二</span></p>
    <p title="aaa">一<span title="aaa">二</span></p>
    <div id="id6">
      <p id="id7"><strong id="id8">Strong<span id="id9">二</span></strong></p>
    </div>
  </body>
</html>

我们从它里面选择几个元素组成数组,模拟为选择器上一次选取的结果。

  window.onload = function(){
    var $ = function(id){
      return document.getElementById(id);
    }
 
    var a = $("id1");
    var b = $("id2")
    var c = $("id3")
    var d = $("id4")
    var e = $("id5")
    var f = $("id6")
    var g = $("id7")
    var h = $("id8")
    var arr = [a,b,c,d,e,f,g,h];
}

由于网页很简单,我们一眼就看得出,最终应该从中筛选出:a,d,f。

要实现这个目标,我们必须先对数组进行排序,让元素安排它们在页面上的位置从上到下,从左到右排序。这简单, 我们可以通过以下方法实现:

var sortOrder = function(){
  if(!+"\v1"){
    return function( a, b ) {
      return a.sourceIndex - b.sourceIndex;
    }
  }else{
    return function(a,b){
      a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
    }
  }
}();

我们还需要检测它们是否存在包含关系:

var contains = function(a,b){
     if(!+"\v1"){
       return a === b ? false : a.contains(b);
     }else{
       return !!(a.compareDocumentPosition(b) & 16)
     }
   }

最后我们进行两两比较,把儿子与孙子都找出来,打上标记,没有标记的就是我们要找的祖先,那么从这些祖先获取的后代集合就一定没有重复元素了!

arr.sort(sortOrder);
var getAncestor = function(array){
  for (var i = 0,n=array.length; i < n; i++) {
    for (var j = n - 1; j > i; j--) {
      var a = array[i],b=array[j]; 
      if (contains(a,b)) {        
        b.no = 1;                 
      }else if(contains(b,a)) {   
        a.no = 1
      }
    }
  }
  var result = [],ri= 0
  for(var k=0;k<n;k++){
    if(!array[k].no){
      result[ri++] = array[k]
    }
  }
  return result;
}
 
var ancestor= getAncestor(arr)

但是这样做有个致命的缺陷,就是只能筛选一次,下一次这个no私有属性将成为干扰因素,但移除私有属性费时费劲,因此建议使用uuid技术进行筛选。

arr.sort(sortOrder);
var uuid = 0
var getAncestor = function(array){
  var remove = {},uid ;
  for (var i = 0,n=array.length; i < n; i++) {
    for (var j = n - 1; j > i; j--) { //比如一共有五个元素,那么每趟为
      var a = array[i],b=array[j]; 
      if (contains(a,b)) {        
        uid = b.uuid || (b.uuid = "dom-"+uuid++) ;
        remove[uid] = 1;
      }else if(contains(b,a)) {    
        uid = a.uuid || (a.uuid = "dom-"+uuid++);
        remove[uid] = 1;
      }        
    }
  }
  var result = [],ri= 0
  for(var k=0;k<n;k++){
    if(!remove[array[k].uuid]){
      result[ri++] = array[k]
    }
  }
  return result;
}
 
var ancestor = getAncestor(arr)
for(var i=0,n=ancestor.length;i<n;i++){
  alert(ancestor[i].id)
}

如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码

posted on   司徒正美  阅读(2718)  评论(0编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示