数组去重

做~自己de王妃 提交于 2020-01-13 20:06:25

数组去重就是将一个数组中的相同的元素删除,只保留其中的一个。这里的相同,其实是一个陷阱,有好多同学认为值相等即为相同,而忽略了类型的判断。

下面介绍13种原生方式实现数组去重,当中涉及ES6,ES5两种标准,has,Map,filter,reduce,call,apply,set,push,from,indexOf,sort等函数,及函数式编程,原型函数,构造函数等概念。

一、对象键值对解法

解法1

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>对象键值对去重,适用于数组或者数组对象</title>
</head>

<body>
    未区分数字和字符串,耗时13ms,超级快。
    <script type="text/javascript">
    function removeSame(arr) { 
        // 构建一个新数组,存放结果 
        var newArray = [];
        //创建一个空对象
        var object = {};
        // for循环时,每次取出一个元素与对象进行对比
        // 如果这个对象不重复,将它存放到结果数中
        // 同时把这个元素的内容作为对象的一个属性,并赋值为true,存到对象中
        for (var i = 0; i < arr.length; i++) {
            // 检测object对象中是否包含遍历到的元素值
            if (!object[arr[i]]) {
                // 如果不包含,将存入对象的元素的值推入到结果数组中 
                newArray.push(arr[i]);
                // 如果不包含,存入object对象中该属性名的值设置为true 
                object[arr[i]] = true;
            }
        }
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[11][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5]
    console.log(removeSame(arr)); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = removeSame(arr);
        var tEnd = (new Date()).getTime();
        console.log('对象键值对去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法2

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>对象键值对去重</title>
</head>

<body>
    有区分数字和字符串,耗时340ms,占用内存大。
    <script type="text/javascript">
    Array.prototype.removeSame = function() {
        // 构建一个新数组,存放结果 
        var newArray = [];
        //创建一个空对象
        var object = {};
        // for循环时,每次取出一个元素与对象进行对比
        // 如果这个对象不重复,将它存放到结果数中
        // 同时把这个元素的内容作为对象的一个属性,并赋值为1,存到对象中
        for (var i = 0; i < this.length; i++) {
            // 检测object对象中是否包含遍历到的元素值
            if (!object[typeof(this[i]) + this[i]]) {
                // 如果不包含,将存入对象的元素的值推入到结果数组中 
                newArray.push(this[i]);
                // 如果不包含,存入object对象中该属性名的值设置为1 
                object[typeof(this[i]) + this[i]] = 1;
            }
        }
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
    console.log(arr.removeSame());

    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('对象键值对去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法3

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>对象键值对去重</title>
</head>

<body>
    有区分数字和字符串,耗时1391ms。
    <script type="text/javascript">
    Array.prototype.removeSame=function() {
        // 构建一个新数组,存放结果 
        var newArray = [];
        //创建一个空对象
        var object = {};

        this.forEach(function(value) {
            var type = Object.prototype.toString.call(value).match(/\s(\w+)/)[1].toLowerCase();
            if (!((type + '-' + value) in object)) {
                object[type + '-' + value] = true;
                newArray.push(value);
            }
        })
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5 ,"1" ,"2"]
    console.log(arr.removeSame());

    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('对象键值对去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

二、ES6解法

解法1

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>ES6之from去重</title>
</head>

<body>
    更简单,更优化,有区分数字和字符串,耗时165ms。
    <script type="text/javascript">
    function removeSame(arr){
        return Array.from(new Set(arr));// return [...new Set(arr)]也可以实现,效率差不多。
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
    console.log(removeSame(arr)); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = removeSame(arr);
        var tEnd = (new Date()).getTime();
        console.log('ES6之from去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法2

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>ES6之filter去重</title>
</head>

<body>
    更简单,更优化,有区分数字和字符串,耗时171ms。
    <script type="text/javascript">
    function removeSame(arr){
        const seen=new Map();
        return arr.filter((a) => !seen.has(a) && seen.set(a,1));
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
    console.log(removeSame(arr)); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = removeSame(arr);
        var tEnd = (new Date()).getTime();
        console.log('ES6之filter去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法3

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>ES6之filter去重</title>
</head>

<body>
    更简单,有区分数字和字符串,耗时22355ms。
    <script type="text/javascript">
    function removeSame(arr){
        return arr.filter((v,i,context) => context.indexOf(v) === i);
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
    console.log(removeSame(arr)); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = removeSame(arr);
        var tEnd = (new Date()).getTime();
        console.log('ES6之filter去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

三、for,foreach,Array解法

解法1

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>forEach循环去重</title>
</head>

<body>
    有区分数字和字符串,耗时14778ms。
    <script type="text/javascript">
    function removeSame() { 
        var newArray = [];
        this.forEach(function(index) {
            if (newArray.indexOf(index) == -1) {
                newArray.push(index);
            }
        });
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
    console.log(removeSame.apply(arr));

    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = removeSame.call(arr);
        var tEnd = (new Date()).getTime();
        console.log('forEach循环去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法2

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>排序后for循环去重</title>
</head>

<body>
    有区分数字和字符串,耗时720ms。
    <script type="text/javascript">
    Array.prototype.removeSame = function() {
        //原数组先排序
        this.sort();
        // 构建一个新数组,存放结果 
        var newArray = [];
        for (var i = 1; i < this.length; i++) {
            // 检查原数中的第i个元素与结果中的最后一个元素是否相同 
            // 因为排序了,所以重复元素会在相邻位置
            if (this[i] !== newArray[newArray.length - 1]) {
                // 如果不同,将元素放到结果数组中 
                newArray.push(this[i]);
            }
        }
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13]["1", 1, 2, "2", 3, 32, 34, 4, 5, 56, "a", "b", "c"]
    console.log(arr.removeSame());

    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('排序后for循环遍历去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法3

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>for循环去重</title>
</head>

<body>
    有区分数字和字符串,耗时14907ms。
    <script type="text/javascript">
    Array.prototype.removeSame = function() { 
        // 构建一个新数组,存放结果 
        var newArray = [];
        // 遍历数组
        for (var i = 0; i < this.length; i++) {
            //如果当前数组的第i值保存到临时数组,那么跳过
            var index = this[i];
            //如果数组项不在结果数组中,将这个值推到结果数组
            if (newArray.indexOf(index) === -1) {
                newArray.push(index);
            }
        }
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5 ,"1" ,"2"]
    console.log(arr.removeSame()); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('for循环去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法4

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>双重for循环去重</title>
</head>

<body>
    未区分数字和字符串,耗时34762ms。
    <script type="text/javascript">
    Array.prototype.removeSame = function() { // 构建一个新数组,存放结果 
        var newArray = [this[0]];
        // for循环,每次从原数组中取出一个元素 
        // 用取出的元素循环与结果数组对比 
        for (var i = 1; i < this.length; i++) {
            var repeat = false;
            for (var j = 0; j < newArray.length; j++) {
                // 原数组取出的元素与结果数组元素相同 
                if (this[i] == newArray[j]) {
                    repeat = true;
                    break;
                }
            }
            if (!repeat) {
                // 如果结果数组中没有该元素,则存放到结果数组中 
                newArray.push(this[i]);
            }
        }
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[11][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5]
    console.log(arr.removeSame()); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('双重for循环去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法5

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>双重for循环去重</title>
</head>

<body>
    有区分数字和字符串,耗时69240ms。
    <script type="text/javascript">
    Array.prototype.removeSame = function() {
        // 构建一个新数组,存放结果 
        var newArray = [];
        // 遍历整个数组
        for (var i = 0; i < this.length; i++) {
            // 遍历是否有重复的值
            for (var j = i + 1; j < this.length; j++) {
                // 如果有相同元素,自增i变量,跳出i的循环
                if (this[i] === this[j]) {
                    j = ++i;
                }
            }
            //如果没有相同元素,将元素推入结果数组中
            newArray.push(this[i]);
        }
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13]["a", 1, 3, 4, 56, 32, 34, 2 ,"b","c", 5 ,"1", "2"]
    console.log(arr.removeSame());

    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('双重for循环去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

四、ES5解法

解法1

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Array.prototype.reduce去重</title>
</head>

<body>
    有区分数字和字符串,耗时15258ms。
    <script type="text/javascript">
    Array.prototype.removeSame = function() { 
        return this.reduce(function(newArray, index) {
            if (newArray.indexOf(index) < 0) {
                newArray.push(index);
            }
            return newArray;
        }, []);
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
    console.log(arr.removeSame());

    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('Array.prototype.reduce去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法2

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Array.prototype.filter去重</title>
</head>

<body>
    未区分数字和字符串,耗时801ms
    <script type="text/javascript">
    Array.prototype.removeSame = function() { 
        var newArray = this.sort();
        return newArray.filter(function(v,i,context){
            return v != context[i+1];
        });
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[11][1, "2", 3, 32, 34, 4, 5, 56, "a", "b", "c"]
    console.log(arr.removeSame()); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('Array.prototype.filter去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>

解法3

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Array.prototype.filter去重</title>
</head>

<body>
    有区分数字和字符串,耗时68053ms
    <script type="text/javascript">
    Array.prototype.removeSame = function() { 
        var newArray;
        newArray = this.filter(function(ele,i,arr) {
            return arr.indexOf(ele) === i;
        });
        return newArray;
    }
    //1、用简单数组测试功能
    var arr = [1, 2, 3, 4, 'a', 'b', 1, 3, 4, 56, 32, 34, 2, 'b', 'c', 5, '1', `2`];
    // 输出:Array[13][1, 2, 3, 4, "a", "b", 56, 32, 34, "c", 5, "1", "2"]
    console.log(arr.removeSame()); 
    
    //2、用随机大额数组测试性能
    function removeSameTime(arr) {
        var tStart = (new Date()).getTime();
        var re = arr.removeSame();
        var tEnd = (new Date()).getTime();
        console.log('Array.prototype.filter去重耗时是:' + (tEnd - tStart) + 'ms');
        return re;
    }

    function testMain() {
        var arr = [];
        for (var i = 0; i < 1000000; i++) {
            //生成随机数组
            arr.push(Math.round(Math.random(i) * 10000));
        }
        //调用去重方法,打印函数执行时间
        removeSameTime(arr);
    }
    testMain();
    </script>
</body>

</html>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!