数组去重 是面试之中非常容易被问到的手写代码题,可以说是“必考题”,我通过在社交论坛上的学习,加以自己对其理解来对这个问题总结归纳。
一、双层循环-值比对
这是最容易想到的方法,简单让值进行比对,建立个新数组,相同的就跳过,不同的就先push进来
Array.prototype.distinct = function(){
var arr = this,
result = [], //定义个新数组
i,
j,
len = arr.length;
for(i = 0; i < len; i++){
for(j = i + 1; j < len; j++){
if(arr[i] === arr[j]){ //如果相等,就直接 跳过( j= ++i; )
j = ++i;
}
}
result.push(arr[i]); //否则就把这个元素push进result数组
}
return result;
}
var arra = [1,2,3,4,4,1,1,2,1,1,1];
arra.distinct(); //返回[3,4,2,1]
二、根据对象属性不能相同
这里大家也是比较熟悉的,判断对象的属性( !obj[arr[i]] ) 或者也可以用typeof。 解题思路
-
首先我们要建立一个JSON 对象
-
建立一个数组用于待会儿存放属性不同的元素
-
在循环当中,一一拿出元素与对象进行比对,到该对象中去访问这个属性,如果对象中无该元素属性,把该元素push进我们建立的数组当中,并且把元素的内容作为对象的属性,并且给它赋值
Array.prototype.distinct = function (){
var arr = this,
i,
obj = {}, //声明一个JSON 对象
result = [], // 声明一个空数组,(也是我们想的到的结果)
len = arr.length;
for(i = 0; i< arr.length; i++){
if(!obj[arr[i]]){ //如果能查找到,证明数组元素重复了
obj[arr[i]] = 1; //给属性赋值为1
result.push(arr[i]); // push进数组
}
}
return result;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,56
三、数组递归
递归算是中比较灵活,常见的方法,其实这个和循环的思路大同小异,主要是递归思路。重复调用函数不见得有很高的效率,但这里只是去重而已,所以我们可以先给数组排序,这样节省了很大功夫。排序这里用到了sort(),接下来就是比较值,这里的处理和双层循环有些不同,这里是用splice()方法删除,没有建立新数组。
Array.prototype.distinct = function (){
var arr = this,
len = arr.length;
arr.sort(function(a,b){ //对数组进行排序才能方便比较
return a - b;
})
function loop(index){
if(index >= 1){
if(arr[index] === arr[index-1]){
arr.splice(index,1);
}
loop(index - 1); //递归loop函数进行去重
}
}
loop(len-1);
return arr;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,56,45,56];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,45,56
四、利用indexof和forEach,还有filter
indxof(),filter()是啥?书看的少了,你我之间,情同手足。
-indexOf(): 返回某个指定的字符在某个字符串中首次出现的位置。如果没有找到就返回-1;
filter(): 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
由于indxof返回不了元素,所以这里还是要建立数组,我们要去重,换句话意思是我们要的就是 返回-1 , 这还不爽,外面用foreach()每个元素,直接从当前元素的下一个元素(index+1)去找,返回-1就把这个value push进数组,组成新的数组。
Array.prototype.distinct = function (){
var arr = this,
result = [],
len = arr.length;
arr.forEach(function(v, i ,arr){ //这里利用map,filter方法也可以实现
var bool = arr.indexOf(v,i+1); //从传入参数的下一个索引值开始寻找是否存在重复
if(bool === -1){
result.push(v);
}
})
return result;
};
var a = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,2,3,3,2,2,1,23,1,23,2,3,2,3,2,3];
var b = a.distinct();
console.log(b.toString()); //1,23,2,3
然后filter(), filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。简而言之就是它是一个“肾脏”,在不断地“过滤”,留下的都是我们要的。
var arr = [1, 2, 2, 3, 4, 5, 5, 6, 7, 7,8,8,0,8,6,3,4,56,2];
var arr2 = arr.filter((x, index,self)=>{ // self:表示该数组对象 x: 表示当前对象 index:下标
return self.indexOf(x)===index
})
console.log(arr2); //[1, 2, 3, 4, 5, 6, 7, 8, 0, 56]
五、ES6 的set
离谱!这是什么! set() 竟然是个数据结构 我们通过Array.from方法可将Set结构转为数组,然后 扩展运算符和 Set 结构相结合,就可以去除数组的重复成员。
let arr = [1,2,3,3];
let resultarr = [...new Set(arr)];
console.log(resultarr); //[1,2,3]
三行代码直接干完,确实有点离谱,但仔细去学习,刨析。发现扩展运算符内部就是使用的 for..of循环,set()方法又是内部成员的值是唯一的,set就直接通过循环之后,把重复的值都过滤了。
六、既然是数组,那不妨延申一下,我们多一个数组,数组合并再去重
我其实就是想借此说一下concat()有合并数组方法,这也是我最近通过老师那边的课程,才学习到的。其实你可能想到了它的应用场景,就是在写数据库sql语句的时候,对字符串进行连接,不经意间就深入的去了解了一下concat,没想到也能用于数组合并。
先数组合并
function concatArr(arr1, arr2){
var arr = arr1.concat(arr2);
return arr;
}
再进行去重,那就可以随便选择上面任意一种方法就行了