【离骚】之 JS数组去重

1,029 阅读4分钟

理一遍去重,希望可以像离骚前两句话一样这辈子可以脱口而出。

                                     --- 长太息以掩涕兮,哀民生之多艰

1、ES6 new Set去重

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function unique(arr) {
    return Array.from(new Set(arr))
}
console.log(unique(list))

// [4, "lalala", true, undefined, "true", null, 0, {}, {}, [], [], NaN]
// 0.0029296875ms

简化一下
[...new Set(list)]
  • Array.from 将 类似数组的对象可遍历的对象转化为真正的数组
  • Set ES6 新的数据结构,set对象是值的集合,不会储存重复的元素
  • 无法对{}[]去重

2、嵌套循环去重(原始)

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]

function uni (arrList) {
    // reasonList 用来储存去重后的数组
    let reasonList = []
    for(var i = 0; i < arrList.length; i++) {
        for (var j = 0; j < reasonList.length; j++) {
            // 当找到两个数组中有相同的就停止循环
            if (arrList[i] === reasonList[j]) {
                break
            }
        }
        // 如果没有相同的,执行完循环j === reasonList.length
        if (j === reasonList.length) {
            reasonList.push(arrList[i])
        }
    }
    return reasonList
}
console.log(uni(list))
//[4, "lalala", true, undefined, "true", null, 0, {}, {}, [], [], NaN, NaN]
//0.025146484375ms

嵌套循环,原始数组arrList和一个新的reasonList,判断arrList[i]和reasonList[j]是否相等,如果不相等,就说明元素是唯一的,循环执行完j的长度等于reasonList[j]的长度,把唯一的元素push到新的数组里。

3、indexof去重(嵌套循环的简化)

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni (arrList) {
    let reasonList = []
    for(var i = 0; i < arrList.length; i++) {
        // 
        if (reasonList.indexOf(arrList[i]) === -1 )
        {
            reasonList.push(arrList[i])
        }
    }
    return reasonList
}
console.log(uni(list))
//[4, "lalala", true, undefined, "true", null, 0, {}, {}, [], [], NaN, NaN]
//0.026123046875ms

4、indexOf去重(判断indexOf的值是否与元素索引值相等)

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni (arrList) {
    let reasonList = []

    for(var i = 0; i < arrList.length; i++) {
        if (arrList.indexOf(arrList[i]) === i )
        {
            reasonList.push(arrList[i])
        }
    }
    return reasonList
}
console.log(uni(list))
//[4, "lalala", true, undefined, "true", null, 0, {}, {}, [], []]
//0.025146484375ms

leetcode原地删除重复元素,不实用额外的数组空间

var removeDuplicates = function(nums) {
    for(let i = 0; i < nums.length; i++) {
        if (nums.indexOf(nums[i]) !== i) {
            nums.splice(i, 1)
            i--
        }
    }
    return nums.length
};

如果第一次出现的索引值和元素索引值一样则,push到新的数组

  • indexOf 返回调用它的String/Array对象中第一次出现的指定值的索引

5、排序去重(先排序,比较当前元素和前一个元素是否相同)

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni (arrList) {
    let reasonList = []
    
    arrList.sort()
    for(var i = 0; i < arrList.length; i++) {
           if(arrList[i+1] !== arrList[i]) {
                reasonList.push(arrList[i+1])
            }
    }
    return reasonList
}
console.log(uni(list))
//[], 0, 4, NaN, NaN, {}, {}, "lalala", null, true, "true", undefined]
//0.039775390625ms
  • 可以对[]去重,[] !== []返回true
  • [](object)== ![](Boolean) 转成布尔类型,转成数字类型做比较
  • sort() 用原地算法对数组的元素进行排序

6、排序去重(头尾比较去重,和5实际上一样,多定了一个变量)

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni (arr) {
    var res = [],
        end;
        
    arr.sort()
    end = arr[0]
    res.push(arr[0]) 
    
    for(var i=1; i < arr.length; i++){
        // 这里需要用!==
        // [] == 0 返回true
        if(arr[i] !== end) {
            res.push(arr[i])
            end=arr[i]
        }
    }
    return res
}
//[[], [], 0, 4, NaN, NaN, {…}, {…}, "lalala", null, true, "true", undefined]
//0.02392578125ms

7、 filter去重

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]

function uni(arr){
    var reasultList = arr.filter(function(item,index,arr){
        return arr.indexOf(item) === index
    })
return reasultList
}
//[4, "lalala", true, undefined, "true", null, 0, {…}, {…}, Array(0), Array(0)]
// 0.031005859375ms
  • NaN直接去掉了

8、reduce去重

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni(arr){
    return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
//[4, "lalala", true, undefined, "true", null, 0, {…}, {…}, Array(0), Array(0), NaN]
//0.003173828125ms
  • 可以对NaN去重

9、利用对象属性不会重复去重(for...of + Object )

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni(arr) {
    var res = []
    let obj = {}

    for (let i of arr) {
        if (!obj[i]) {
            res.push(i)
            obj[i] = 1
        }
    }
    return res
}

// [4, "lalala", true, undefined, null, 0, {}, [], NaN]
// 0.03369140625ms
  • 这个方法可以对[]{}NaN去重,但是true会直接去掉,慎用
  • 有人说这个比set快可能数据量不到 看不到效果

10、for...of + includes

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni(arr) {
	var res = []
	for (let i of arr) {
	    !res.includes(i) && res.push(i)
	}
	return res
}
uni(list)
// [4, "lalala", true, undefined, "true", null, 0, {}, {}, [], [], NaN]
// 0.02197265625ms
  • 可以对NaN去重

11、map去重

var list = [4, 4, "lalala", "lalala", true, true, undefined, 'true', 'true', undefined, undefined, null, null, 0, 0, {}, {}, [], [], NaN, NaN]
function uni(arr) {
    let map = new Map()
    let array = new Array()
        for (let i = 0; i < arr.length; i++){
            if(map.has(arr[i])) {
                map.set(arr[i], true)
            } else {
                map.set(arr[i], false)
                array.push(arr[i])
            }
        }
    return array
}
console.log(uni(list))
//[4, "lalala", true, undefined, "true", null, 0, {}, {}, [], [], NaN]
//0.033203125ms

小结

Set是比较快的,但是reduce的方式看上去和set时间差不多
由于是用浏览器运行的而且数据少,有空用node跑一遍再看看。