美文网首页Web前端之路
JS中去重方法的探讨

JS中去重方法的探讨

作者: 错码匠 | 来源:发表于2017-05-24 13:48 被阅读219次

    说到去重有很多的实现,在ES6下根本不是问题,然而在ES6之前……习惯性的思路是 copy 一个新的集合并与原始集合做遍历、比对,类似如下这种实现方法:

        var uniq1=function(arr){
            var temp=[],
                item,
                i,n;
    
            for(i=0;i<arr.length;i+=1){//开始去重
                item=arr[i];
                temp.push(item);
                for(n=0;n<temp.length;n+=1){
                    if(item===temp[n-1]){//如temp与arr中的元素重复则删除
                        temp.splice(temp.length-1,1);
                    }
                }
            }
            return temp;
        };
    

    上面这个例子会创建一个临时的空数组对象,在将元素逐个放入其中时与前一个元素作比对,如果值相同则从临时数组中剔除,直至遍历完所有比对对象……这个方法尽可能的优化了性能,但是出现了嵌套循环,代码实现逻辑复杂、对部分阅读者并不友好对吗?下面介绍一种或许可以减压并且性能表现不俗的实现方法。

    先说说思路,我们习惯对数组元素逐一比较后取得不重复值的方式来实现去重,这让编程者思维局限在数组里。其实js世界为我们提供了现成的去重偏方——对象{},因为对象的键名是唯一的,我们利用这一特性,把值作为对象的键名就可以实现去重,于是:

        var uniq2=function(arr){
            var i,temp=[],
                key,newArr=[];
    
            for(i=0;i<arr.length;i+=1){//遍历数组,将值作为键名放入对象中
                temp[arr[i]] = (temp[arr[i]]+1)||1;//对象值随便赋,用作重复次数的统计是个不错的选择
            }
    
            for(key in temp){//把生成的临时对象转回数组
                newArr.push(key);
            }
    
            return newArr;
        };
    

    逻辑清晰,效果很好。由于是直接对对象键名的覆盖,无需比对重复值,循环体的运算复杂度大大减少,这在做大量数据操作时对性能的提升会很明显,因为无论如何仅仅是对数组的一次遍历而已。我们写个简单的测试得到如下结果:

    测试结果1

    优势明显!但是带来一个新问题,我们遍历结果发现所有的值都变成了字符串!还有,如果是对象集合的去重呢?我们知道对象的键名是字符串,不能直接用对象字面量,真是没有银弹!怎么办?我们依旧沿袭“偷懒的作风”,用js给我们提供的现成方法JSON.stringify()把对象转成字符串,在去重完成后用JSON.parse()方法转回对象字面量……好吧,这太容易了,所以,我再偷下懒,完整的实现代码就由各位自由发挥吧,很容易不是吗。

    据说写个ES6代码在用Babel转换下不就好了……然而用户需求是无止境的依然有人不放弃对<ie8的支持。并且我发现第二种方法即使加上JSON的解析,在性能上依然优于[...new Set(arr)]

    测试结果2

    可能这点数据量还不足以体现这种方法的巨大优势,我们加点料再测一次:

    测试结果3

    完胜啊!

    关于去重还有很多话题可以展开,比如算法、对结果排序的影响等,但归根结底还是性能优化、高效处理。这是个很有趣味的主题!

    相关文章

      网友评论

        本文标题:JS中去重方法的探讨

        本文链接:https://www.haomeiwen.com/subject/qmanxxtx.html