数组去重的110种方法

396 阅读6分钟

数据去重是面试中比较容易见到的问题,今天我们就来总结一下数据去重的方法。我们以arr[1,2,3,4,1,2]数组为例,去掉数组中重复的值。

001. 双重for循环

既然是去掉数组中重复的值,肯定需要遍历数组中的值,检查哪些值是唯一哪些是重复的。于是,我们就可以新建一个数组newArr,遍历原数组中的值,每拿到一个值就放入新数组中,但是放入前需要判断该值是否已经存在,这时候再遍历一遍新数组中的值即可。

image.png 如图,放入1时检查新数据是否已有该值,若有就不添加,否则添加进新数组,这样一来新数组中的每个值就唯一了。具体代码实现如下;

const arr = [1, 2, 3, 4, 2, 1]

function unique() {
  let newArr = []
  for (let i = 0; i < arr.length; i++) {
    //判断新数组是否已经具有该值
    for (var j = 0; j < newArr.length; j++) {
      if (arr[i] === newArr[j]) {
        break
      }
    }
    if (j === newArr.length) {
      newArr.push(arr[i])
    }
  }
  return newArr
}

console.log(unique(arr));

其中需要注意的是,向新数组中添加值时需要判断是否已经遍历完(即j === newArr.length),因为如果不判断的话,一个值加入时就算找到与之相等的值跳过当前循环也会添加进新数组。

010. for + indexOf

arr.indexOf(x)是用来判断arr数组中是否有x这个元素,如果有返回其第一次出现的下标,反之返回-1。

image.png 既然indexOf可以用于返回元素下标,没有就返回-1。那么不就可以用来数组去重吗。新数组中没有该值就会返回-1,那么该元素就可以加入新数组中。具体代码如下;

const arr = [1, 2, 3, 4, 2, 1]

function unique() {
  let newArr = []
  for (let i = 0; i < arr.length; i++) {
    //newArr数组中没有 arr[i]这个值就返回-1
    if (newArr.indexOf(arr[i]) === -1) {
      newArr.push(arr[i])
    }
  }
  return newArr
}

console.log(unique(arr));

011. for + includes

includes可以用来判断该数组中是否包含这个值,包含返回true,贩子false。

image.png 所以直接替换上面的indexOf即可,如下;

const arr = [1, 2, 3, 4, 2, 1]

function unique() {
  let newArr = []
  for (let i = 0; i < arr.length; i++) {
    //如果新数组中没有该值
    if (!newArr.includes(arr[i])) {
      newArr.push(arr[i])
    }
  }

  return newArr
}

console.log(unique(arr));

100. filter + sort

这种就比前面的稍微高级一点了,代码也更加简洁。sort是用来排序的大家都知道,那么filter是用来干嘛的呢?翻译过来是过滤的意思,也就是可以用来过滤出符合要求的元素,有三个参数,分别为(item,index,arr),分别代表什么呢?我们用下面代码输出来看一下。

const arr = [1, 2, 3, 4, 2, 1]
arr.filter((item, index, arr) => {
  console.log(item, index, arr);
})

结果如下;

image.png

用法如下:

const arr = [1, 2, 3, 4, 2, 1]
const arr2 = arr.filter((item, index, arr) => {
  return item <= 2
})  //过滤
console.log(arr2);   //[ 1, 2, 2, 1 ]

过滤出数值小于等于2的元素。

再来看数据去重,我们可以先将数组排序,然后往新数组中添加元素时,判断与前一个元素是否相等(这时候就可以用到filter里面参数arr),不相等添加,相等则不添加继续遍历下一个元素,具体代码如下。

const arr = [1, 2, 3, 4, 1, 2]
function unique() {
  let newArr = [...arr].sort() 
  newArr = newArr.filter((item, index, array) => {
    return index === 0 || item !== array[index - 1]
  })
  return newArr
}

console.log(unique());

可简写成;

const arr = [1, 2, 3, 4, 2, 1]
function unique() {
  let newArr = [...arr]  //使用扩展运算符创建arr的一个浅拷贝
  // [1, 1, 2, 2, 3, 4]
  return newArr.sort().filter((item, index, array) => {
    return index === 0 || item !== array[index - 1]  //return出该值与前一个值不相等的元素
  })
}
console.log(unique());

let newArr = [...arr]就是将arr所有元素复制到newArr中。然后再排序,再用fliter遍历,过滤出第一个元素和该值与前一个值不相等的元素赋给newArr,这样newArr就是原数组去重后的结果了。

unique函数里面还可简写成return [...arr].sort().filter((item, index, array) => !index || item !== array[index - 1])一句话搞定,因为对于箭头函数,不加{}的话,他就会自带return,如下;

image.png

101. fliter + {}

不重复,可以联想到对象上不会出现俩个相同的key值,如果出现了,那么后一个就会覆盖掉前一个的值。如下;

const obj = {
  name: '彭于晏',
  name: '屏幕前的你',
  age: '18',
  girlfriend: '章若楠'
}
console.log(obj);

当有俩个相同的name(key值),后面的name,就会覆盖掉前面的name,也就是屏幕前的你会覆盖掉彭于晏,输出结果就是屏幕前的你了:

image.png 那么我们直接将数组中每个值直接放入对象里面,再输出对象的每个key值。我们可以使用Object.keys(obj)将对象中的值加入到数组中保存。

const obj = {
  1: 0,
  2: 1,
  3: 2,
  4: 3,
  1: 4,
  2: 5
}

console.log(Object.keys(obj));  //[ '1', '2', '3', '4' ]

不过是字符串类型,我们可以用map方法将其转化为数字类型。

console.log(Object.keys(obj).map(Number));  //[ 1, 2, 3, 4 ]

然后我们就可以运用对象来解题了。我们可以加入元素时将该key的值设为true,这样判断条件就可以判断obj对象里面的key对应的值是true还是false,如果是false,说明该值还没有被加入。具体代码如下;

let arr = [1, 2, 3, 4, 1, 2]
function unique() {
  let obj = {}
  for (let i = 0; i < arr.length; i++) {
    //如果 obj[arr[i]] 为 false 说明之前没加过该值
    if (!obj[arr[i]]) {
      obj[arr[i]] = true
    }
  }
  return Object.keys(obj).map(Number)
}
console.log(unique());  //[ 1, 2, 3, 4 ]

既然我们知道filter,那么我们就可以使用一下filter使得代码更加简洁,如下。

let arr = [1, 2, 3, 4, 1, 2]
function unique() {
  let obj = {}
  return arr.filter((item, index, array) => {
    return obj[item] ? false : (obj[item] = true)
  })
}
console.log(unique());  //[ 1, 2, 3, 4 ]

return obj[item] ? false : (obj[item] = true)

三元运算符,如果 obj[item] 是true就说明已经存在该值,返回false,这样filter会排除这个元素,否则就将该值加入 obj 的 key 里面并将其值设为true。

110. Set

最后让我们来介绍第110种数组去重的方法,也就是使用Set数据结构。它是一种特殊的对象,既像数组又像对象,因为它只有key,没有value,所以里面的值不能重复,可以用has方法判断是否存在某个值。

let s = new Set()
s.add(1)
s.add(2)
s.add(3)
s.add(2)
console.log(s);    //Set(3) { 1, 2, 3 }
console.log(s.has(3));  //true

所以可以利用这个没有重复值的特性来解决数组去重的问题。直接将数组加入到Set上,再解构输出出来即可。

const arr = [1, 2, 3, 4, 1, 2]
let s = new Set(arr)
console.log(s);  //Set(4) { 1, 2, 3, 4 }

然后用[...s]解构出来即可,具体代码是实现如下。

let arr = [1, 2, 3, 4, 1, 2]
function unique() {
  return [...new Set(arr)]
}

console.log(unique());    // [ 1, 2, 3, 4 ]

好了,今天的一一零种方法就介绍到这里了,你学废了吗?先别着急划走。

image.png