手写代码之-数组去重

181 阅读3分钟

数组去重 是面试之中非常容易被问到的手写代码题,可以说是“必考题”,我通过在社交论坛上的学习,加以自己对其理解来对这个问题总结归纳。

一、双层循环-值比对

这是最容易想到的方法,简单让值进行比对,建立个新数组,相同的就跳过,不同的就先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。 解题思路

  1. 首先我们要建立一个JSON 对象

  2. 建立一个数组用于待会儿存放属性不同的元素

  3. 在循环当中,一一拿出元素与对象进行比对,到该对象中去访问这个属性,如果对象中无该元素属性,把该元素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()是啥?书看的少了,你我之间,情同手足。

OIP.jpg

-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;
}

再进行去重,那就可以随便选择上面任意一种方法就行了

总结

其实自己也是个小白,只是通过学习,操作,然后总结,这种方法来提升自己,其实还有很多不足之处,望各位朋友多多指正