Skip to content

1.双for循环(拿当前项和后面的每一项比较,重点:数组塌陷和性能优化)

js
function unique (array) {
  for (let i = 0; i < array.length - 1; i++) {
    // 每一次拿出来的和后面每一项比较
    for (let j = i + 1; j < array.length; j++) {
      if (array[i] === array[j]) {
        array.splice(j, 1)
        // splice存在问题:1.数组塌陷 2.性能(如果删除的这一项后面还有1000万项,这1000万项的索引都要向前移一位)
        // 原数组[1, 2, 1, 1, 2]
        // i = 1; j = 2时 删除第二项,数组塌陷,后面索引都往前移一位
        // [1, 2, 1, 1, 2] => [1, 2, 1, 2]
        // j++ => j = 3, 直接跳过了修改后的原始数组第二项的1
        // 解决办法 先让j--,之后再j++,相当于没加没减,下一轮还是和当前索引项的元素比较,
        // 但是性能上没有优化
        j--
      }
    }
  }
  return array
}
js
function unique (array) {
  for (let i = 0; i < array.length - 1; i++) {
    for (let j = i + 1; j < array.length; j++) {
      if (array[i] === array[j]) {
        // 性能优化
        // 当前项值是重复的,但是不删除,让当前项的值等于最后一项的值
        // 再把最后一项删除
        // [1, 1, 2, 1, 3] => [1, 3, 2, 1, 3] => [1, 3, 2 ,1]
        // 下一轮比较时:还要和当前的索引比,因为当前索引项值变为最后一项了
        array[j] = array[array.length - 1]
        array.length--
        i--
      }
    }
  }
  return array
}

2.单for循环 + 存储容器

js
function unique2 (array) {
  if (!Array.isArray(array)) throw new Error('argument must be an array')

  const resArr = []
  for (let i = 0; i < array.length; i++) {
      if (resArr.indexOf(array[i]) === -1) resArr.push(array[i])
  }
  return resArr
}

3.对象键值对方式,分别取出每一项的值作为对象的属性名存储,每次存储前看对象中是否存在这个属性,以此判断是否重复 1.一个循环,性能更好 2.如果数组出现引用类型则存在问题,因为对象属性名不能是对象 3.数字x和字符串'x'也会被认为是重复的

js
function unique (array) {
  const obj = {}
  for (let i = 0; i < array.length; i++) {
    const item = array[i]
    if (obj.hasOwnProperty(item)) {
      const lastIdx = array.length - 1
      array[i] = array[lastIdx]
      array.length--
      i--
      continue
    }
    obj[item] = item
  }
  return array
}

4.对象键值对 + 存储容器

js
function unique3 (array) {
  if (!Array.isArray(array)) throw new Error('argument must be an array')

  const resArr = []
  const o1 = {}
  for (let i = 0; i < array.length; i++) {
    if (!o1.hasOwnProperty(array[i])) {
      o1.array[i] = true
      resArr.push(array[i])
    }
  }
  return resArr
}

ES6 Set 能够去除引用数据类型的重复

js
function unique (array) {
  return [...new Set(array)]
  // return Array.from(new Set(array))
}

通过正则去重

js
function unique(array) {
  array.sort((a, b) => a - b)
  let str = array.join('@') + '@' // '1@1@1@2@2@3@3@4@5@'
  let reg = /(\d+@)\1*/g
  let result = []
  str.replace(reg, (n, m) => {
    m = Number(m.slice(0, m.length - 1))
    result.push(m)
  })
  return result
}