数组去重的十一种方式

1,854 阅读5分钟

数组中数据全部为基本数据类型

1、Set方法配合展开运算符实现

原数组不会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  return [...new Set(arr)]
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]

思路:利用Set方法不能含有相同值的特性,返回时利用展开运算符(...)返回一个新的数组,因此原数组不会被改变。

2、Set方法配合Array.from方法实现

原数组不会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  return Array.from(new Set(arr))
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]

思路:利用Array.from方法,该方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。因此原数组不会被改变。

3、for循环配合数组indexOf方法实现

原数组不会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  let ary = []
  for(let i = 0, length = arr.length; i < length; i++) {
    if (ary.indexOf(arr[i]) === -1) {
      ary.push(arr[i])
    }
  }
  return ary
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, NaN, null]

思路:利用一层for循环遍历,在for循环的代码块中再使用数组的indexOf方法,来判断新声明的数组中是否存在当前项的索引, 从而达到去重的效果,由于是新声明的数组来存放去重后的数据,因此原数组不会被改变。

4、for循环配合数组includes方法实现

原数组不会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  let ary = []
  for(let i = 0, length = arr.length; i < length; i++) {
    if (!ary.includes(arr[i])) {
      ary.push(arr[i])
    }
  }
  return ary
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]

思路:这种实现方式与上面的indexOf方法实现的一样,原数组也不会被改变。

5、利用Map方法实现

原数组不会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  let map = new Map()
  let ary = []
  for(let i = 0, len = arr.length; i < len; i++) {
    if (map.has(arr[i])) {
      map.set(arr[i], true)
    } else {
      map.set(arr[i], false)
      ary.push(arr[i])
    }
  }
  return ary
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, null] 

思路:利用一层for循环遍历,在for循环的代码块中再使用Map的hasset方法,来判断新声明的数组中是否存在当前项,存在的话将其value设置为true,反之设置为false并使用额外声明的数组变量保存起来,由于是新声明的数组来存放去重后的数据,因此原数组不会被改变。

6、利用Map方法配合数组的filter方法实现

原数组不会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  let map = new Map()
  return arr.filter(item => !map.has(item) && map.set(item, 1))
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]

思路:利用数组的filter方法的特性,该方法会返回一个新的数组,因此原数组不会被改变。

7、利用reduce方法实现

原数组不会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  let ary = arr.reduce((accumulator, current) => {
    return accumulator.includes(current) ? accumulator : accumulator.concat(current)
  }, [])
  return ary
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]

思路:利用数组的reduce方法实现,上面这种实现方式原数组不会被改变。其实reduce方法很强大,可以做很多事情,例如:数组去重、数组降维(拍平)、数组求和等等,这里就不赘述了。

8、利用对象键值对

原数组不会改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  let map = {}
  let ary = []
  for(let i = 0, len = arr.length; i < len; i++) {
    if (map[arr[i]]) continue
    ary.push(arr[i])
    map[arr[i]] = true
  }
  return ary
}
console.log(unique(data)) //  [1, 3, 4, 5, "7", undefined, NaN, null] 

思路:利用for循环,将遍历的子项存放到map对象中,不存在就放到新数组中,这种方式原数组也不会被改变。缺点就是如果string和number类型的值时相等的,那么也会被过滤掉,这种方式限制比较大。

9、双层for循环方法实现(一)

原数组会被改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  if (!arr || arr.length === 0) return []
  for(let i = 0, len = arr.length; i < len; i++) {
    for(let j = i + 1, len = arr.length; j < len; j++) {
      if (arr[i] === arr[j]) {
        arr.splice(j, 1)
        j--
        len--
      }
    }
  }
  return arr
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, NaN, null]

思路:使用双重for循环,外层循环控制次数,内层循环将j变量赋值为i + 1, 在循环体中判断外层循环的索引项与内层循环的索引项是否相等,如果相等 利用splice方法将当前项删除,同时将j和arr数组的长度同时减一,如此往复从而实现去重,由于是直接操作传进来的参数,并将该参数返回出去, 因此原数组会被改变。

10、双层for循环方法实现(二)

原数组不会改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique(arr) {
  let ary = []
  if (!arr || arr.length === 0) return []
  for(var i = 0, len = arr.length; i < len; i++) {
    for(var j = 0, aryLen = ary.length; j < aryLen; j++) {
      if (arr[i] === ary[j]) break
    }
    if (j === aryLen) {
      ary.push(arr[i])
    }
  }
  return ary
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", undefined, 7, NaN, NaN, null]

思路:两层for循环,外层循环遍历的是入参数组,内层循环遍历的是新声明的ary数组,在内层循环体中判断,两个数组中对应的索引值是否相等,相等跳出循环,外层循环体中判断变量jary数组的长度是否相等, 由于是新声明的数组来存放去重后的数据,因此原数组不会被改变。

11、使用sort方法排序后去重

原数组不会改变

const data = [1,3,4,"4",5,"4","7",undefined,7,7, NaN, undefined, NaN, null, null]
function unique (arr) {
  if (!arr || arr.length === 0) return []
  let ary = arr.sort()
  let flag;
  let result = []
  for(let i = 0, len = ary.length; i < len; i++) {
    // 判断是否为第一个元素或者相邻的元素不相同
    if (!i || flag !== ary[i]) {
      result.push(ary[i])
    }
    flag = ary[i]
  }
  return result
}
console.log(unique(data)) // [1, 3, 4, "4", 5, "7", 7, NaN, NaN, null, undefined]

思路:先利用排序方法排序后,再判断相邻两个元素是否相同的思路,一层for循环控制遍历次数,循环体中判断是否为第一个元素或者相邻的元素不相同,条件为真时将数据放入新声明的数组中。由于是新声明的数组来存放去重后的数据,因此原数组不会被改变。

总结

这些方法都是针对一维数组且数组不为对象数组的方法,下面为了方便对比,直接将几种方法进行了对比,这些实现方式最后的结果会有差别,但这不是最重要的,重要的是我们要知道什么场景使用什么方式去解决才好。

方法序号打印结果说明
1[1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]对NaN可以去重
2[1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]对NaN可以去重
3[1, 3, 4, "4", 5, "7", undefined, 7, NaN, NaN, null]对NaN不能去重
4[1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]对NaN可以去重
5[1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]对NaN可以去重
6[1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]对NaN可以去重
7[1, 3, 4, "4", 5, "7", undefined, 7, NaN, null]对NaN可以去重
8[1, 3, 4, 5, "7", undefined, NaN, null]对NaN可以去重,值相同的string和number根据先后顺序会被去重
9[1, 3, 4, "4", 5, "7", undefined, 7, NaN, NaN, null]对NaN不能去重
10[1, 3, 4, "4", 5, "7", undefined, 7, NaN, NaN, null]对NaN不能去重
11[1, 3, 4, "4", 5, "7", 7, NaN, NaN, null, undefined]对NaN不能去重

参考文章

github.com/mqyqingfeng…

www.cnblogs.com/echolun/p/1…