数组去重是一个经典的面试问题,这里记录一下自己的心得和常用的处理方法。
数字类型的数组去重&字符类型数组去重
对于数字类型数组 var arr = [1,2,3,4,3,2,1];
去重或者对于字符类型数组 var arr = ['1','1','a','b','a'];
去重
使用Set去重
function use_set(arr){
return Array.from(new Set(arr));
}
复制代码
先排序再比较去重
1.先将原数组排序,数组会变成这样 [1,1,2,2,3,3,4]
2.逐个的取出数组中的元素,加入另一个临时数组init
中,每次加入的时候判断,如果init
为空,或者init
的最后一个元素与当前要插入的不相等则插入 3.重复2的步骤直到遍历完数组,完成后init
中保存的就是去重之后的数组元素
function reduce_sort(arr){
arr.sort(); //先排序
// 使用reduce挨个比较去重,去重后的结果保存在init数组中
return arr.reduce(function(init,current){
if(init.length === 0 || init[init.length-1]!=current){
init.push(current)
}
return init
},[]);
}
复制代码
使用indexOf过滤
indexOf
可以从前往后查找元素在数组中出现的索引位置,如果没有找到就返回-1
。由于每次的都是从前往后找,当有两个相同的值的时候,indexOf
返回的是前一个值的,而当前索引必然大于indexOf
直接返回,可以根据两者是否相等来过滤数组元素。
function use_filter(arr){
return arr.filter(function(item,index,self){
//从前往后查找对应元素的索引是否与当前索引相等,要是不相等说明之前出现过重复的元素
return self.indexOf(item) === index;
});
}
复制代码
使用Object的键值对去重
使用一个临时的对象obj
来记录数组中的元素是否出现,其中将数组中的元素作为键,出现了就记为ture
。之后通过hasOwnProperty
来判断是否包含这个属性,包含就说明已经存在,不包含就添加为obj
的新属性。
function use_object(arr){
var obj = {};
return arr.filter(function(item){
return obj.hasOwnProperty(item) ? false : (obj[item] = true)
})
}
复制代码
混合数据类型的数组去重
JavaScript中的数组存储的数据类型是可以不同的,也就是说JavaScript中的7种数据类型都可能出现在数组中,此时的去重又变得不一样了
数组中可能出现的数据类型
- null
- undefined
- String
- Number
- Object
- Boolean
- Symbol 另外数组中的元素还可能是数组、函数、日期、正则等其他的特殊对象类型。 对于
indexOf
在底层使用的方法是用===
进行判断,下面是用===
判断是否相等的例子,可以发现有很多类型是不能直接用===
判断的
console.log(null === null); // true
console.log(undefined === undefined); // true
console.log('a' === 'a'); //true
console.log(String('a') === String('a')); // true
console.log(1 === 1); // true
console.log({} === {}); // false
console.log(true === true); // true
console.log(Symbol() === Symbol()); // false
console.log([] === []); // false
console.log(/a/ === /a/); //false
console.log(function(){console.log("1")} === function(){console.log("1")}); //false
console.log(NaN === NaN); // false
复制代码
使用Object键值对去重的时候,需要转成字符串,下面看一下几个转字符串的情况
console.log(1..toString());//1
console.log('1'.toString());//1
console.log([1,function(){console.log("!")},NaN,undefined,null].toString());
//1,function(){console.log("!")},NaN,,
console.log({"a":1}.toString());//[object Object]
复制代码
我只是尝试了几种类型,发现undefined和null在数组中的时候并不能够转成字符串,获取还存在其他的情况我没有发现。下面再试试JSON.stringify()
序列化试试,发现也是有很多元素是不能够直接序列化为字符串的,其他JSON.stringify()的序列化问题参考blog.fundebug.com/2017/08/17/…
console.log(JSON.stringify([1,2,function(){console.log("1")},NaN,undefined,null]))
// [1,2,null,null,null,null
复制代码
先尝试用set去重
无法对对象类型的数据进行去重
var arr = [1,1,'1','1',0,0,'0','0',undefined,undefined,null,null,NaN,NaN,{},{},[],[],/a/,/a/,function(){console.log(1)},function(){console.log(1)}]
function use_set(arr){
return Array.from(new Set(arr));
}
console.log(use_set(arr));
/* [ 1,
'1',
0,
'0',
undefined,
null,
NaN,
{},
{},
[],
[],
/a/,
/a/,
[Function],
[Function] ]
*/
复制代码
将indexOf换成includes
indexOf
的比较是 ===
而inclues
的比较比indexOf
改进的地方是能够判断NaN
If Type(x) is different from Type(y), return false.
If Type(x) is Number, then
a. If x is NaN and y is NaN, return true.
b. If x is +0 and y is -0, return true.
c. If x is -0 and y is +0, return true.
d. If x is the same Number value as y, return true.
e. Return false.
Return SameValueNonNumber(x, y)
复制代码
最后的解决方案
对于对象类型的使用JSON.stringify
序列化为字符串,但是我没有处理不能序列化的情况,然后是用typeof+item
来代替item
避免出现1
和'1'
同时作为key
的情况
function func(arr){
var obj = {};
var res = arr.filter(function(item){
let key;
if(typeof(item)==="object"){
// 对于object使用JSON.stringify
key = JSON.stringify(item)
}else{
// 为了避免 1 和 '1' 这样的情况出现在同一个key中
key = typeof(item) + item;
}
return obj.hasOwnProperty(key) ? false : (obj[key] = true)
})
console.log(obj)
return res
}
复制代码
测试用例
var arr = [1,1,'1','1',0,0,'0','0',undefined,undefined,null,null,NaN,NaN,{},{},{"a":1},{"a":1},[1,2],[1,2],/a/,/a/,function(){console.log(1)},function(){console.log(1)}]
复制代码
测试结果
// 打印的辅助对象
{ number1: true,
string1: true,
number0: true,
string0: true,
undefinedundefined: true,
null: true,
numberNaN: true,
'{}': true,
'{"a":1}': true,
'[1,2]': true,
'functionfunction(){console.log(1)}': true }
// 打印结果
[ 1,
'1',
0,
'0',
undefined,
null,
NaN,
{},
{ a: 1 },
[ 1, 2 ],
[Function] ]
复制代码
简单的记录一下自己的实验结果,感觉还能够改进,还在努力中。。。