数组去重的灵活应用

252 阅读3分钟

手写实现数组去重方法。

  一般这样的面试题还要求的不止一种方法实现,这就需要充分考虑数组的使用了。

方法一: 使用ES6中的 Set() 方法

  Set()是ES6提供的新的数据结构,其类似于数组,但是成员值都是唯一的,没有重复的值。利用这一特性,完成数组的去重操作。这里需要注意的是返回值也是类数组的 Set数据结构,需要转换成数组结构。

    // 这里使用扩展运算符 ... 讲 Set 结构数据转换成数组
    var delRepetition = function (arr) {
        return [...new Set(arr)];
    }

    // 也可以使用 ES6 中的 Array.from() 转换成数组
    var delRepetition = function (arr) {
        return Array.from(new Set(arr));
    }

  使用该方法比较的直观容易理解,唯一需要注意的是兼容性即可。

参考资料: ESMAScript 6 入门

方法二:使用内置函数

  Array内置函数中提供数组元素的查询:

Array.prototype.indexOf() 搜索数组元素,并返回所在的位置,未找到返回 -1;

Array.prototype.includes() 判断数组是否包含指定的值,包含返回 true,不包含返回 false;

  判断当先元素的下标是否等于查询结果的下标,如果是,则表示第一次出现,如果非表示重复出现。可以借助于Array.prototype.filter()函数返回新的数组内容。

    // 如果下标为当前元素下标,表示第一次出现
    // 可以直接放入新的数组当中
    var delRepetition = function (arr) {
        let isN = false;
        let newArr = arr.filter((currentValue, index, array) => {
            // 判断当前元素是否为 NaN
            // 可根据自己的需要删减
            if (currentValue !== currentValue) isN = true;
            return array.indexOf(currentValue) === index
        })
        // 如果包含有NaN元素,最后在添加上
        if (isN) {
            newArr.push(NaN);
        }
        return newArr;
    }

  该方法中包含了特殊类型 NaN 的检测,利用其自身不等于自身的特性进行检测,如果值中包含有NaN元素,最后添加到数组当中。

  当然也可以直接利用数组从左向右计算的特性,返回最后的结果。原理都差不多,返回新数组。

    var delRepetition = function (arr) {
        let isN = false;
        let newArr = arr.reduce((total, currentValue) => {
            if (currentValue !== currentValue) {
                isN = true;
            } else {
                total.indexOf(currentValue) === -1 && total.push(currentValue);
            }
            return total;
        }, []);
        if (isN) newArr.push(NaN);
        return newArr;
    }

方法三:新数组元素查询

  查询元素是否存在需要进行循环遍历,可以使用 Array.prototype.forEach()for ... of 等。也可以使用 for 循环 ,但是需要注意他们之间的区别,虚数组与实数组之间的转换。

  使用数组的内置函数,查询新数组中是否包含有当前元素,如果不包含当前元素,则添加到新的数组当中,如果包含则跳过,这里需要摘出NaN

    var delRepetition = function (arr) {
        let newArr = [],
            isN = false;
        for (let v of arr) {
            if (v !== v) {
                isN = true;
                continue;
            }
            if (!newArr.includes(v)) {
                newArr.push(v);
            }
        }
        if (isN) newArr.push(NaN);
        return newArr;
    }

方法四:排序

  先对元素排序,然后再对比插入:

    var delRepetition = function (arr) {
        let sArr = [].concat(arr).sort();
        let newArr = [],
            isN = false;
        sArr.forEach((value, index, cArr) => {
            if (value !== value) {
                isN = true;
            } else if (index === 0 || value !== cArr[index - 1]) {
                // 如果是第一项,则直接插入
                // 后一项不等于前一项,则插入后一项内容
                newArr.push(value);
            }
        });
        if (isN) newArr.push(NaN);
        return newArr;
    }

  以上方法都进行过实际测试,测试的内容如下,返回结果除元素顺序不一致外,其他雷同。

 delRepetition([
        1, '1', 2, null, null, undefined, undefined, 
        'undefined', NaN, , NaN, 'NaN', 'null', 'true', 
        true, true, false, , false, 'false', ' ', '' ]); 
    // => [1, "1", 2, null, undefined, "undefined", NaN, "NaN", "null", "true", true, false, "false", " ", ""]

  在这里有从网上借鉴了几个比较好的点,如算数运算符的使用 total.indexOf(currentValue) === -1 && total.push(currentValue);这里就利用了 && (和)运算符的特性,如果第一个条件不满足则不会运行第二个条件。