关于大乱炖数组去重的总结

86 阅读9分钟

方法⼀:利用ES6 Set去重 ( ES6中最常用)

1.普通数组

特点: Set 是一种数据结构,它只允许存储唯一的值,因此可以轻松实现数组去重。

const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = Array.from(new Set(arr));
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • Set 本身不能包含重复值,当数组传入 Set 时,重复的元素会自动被过滤掉。
  • 然后使用 Array.from()[...Set]Set 转换回数组。

2.特殊数组

特点:

  • Set 认为 NaN 是相等的,所以会移除重复的 NaN
  • undefined 也可以正常去重。
  • 对于数组和对象元素,Set 会按引用去重,只有引用相同的对象或数组才会被认为是相同的。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
const uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaNundefined 被去重。
  • 引用不同的数组 [1] 和对象 {a: 1} 没有被去重。

方法二:利用for嵌套for,然后splice去重 ( ES5中最常用)

1.普通数组

特点: 这是一个传统的方法,通过双重循环遍历数组,并使用 splice 方法移除重复元素。

const arr = [1, 2, 3, 3, 4, 5, 5];
for (let i = 0; i < arr.length; i++) {
  for (let j = i + 1; j < arr.length; j++) {
    if (arr[i] === arr[j]) {
      arr.splice(j, 1);
      j--; // 由于数组长度减少,索引需要调整
    }
  }
}
console.log(arr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • 外层循环遍历数组中的每个元素,内层循环将该元素与其后面的所有元素进行比较。
  • 如果发现重复的元素,则用 splice 方法移除它。

2.特殊数组

特点:

  • 直接比较元素的值,所以 NaN 不会被认为是相等的,无法去重。
  • undefined 可以去重。
  • 对于数组和对象元素,比较的是引用地址,无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(arr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaN 未被去重,因为 NaN === NaNfalse
  • undefined 被去重。
  • 数组和对象未被去重。

方法三:利用indexOf去重

1.普通数组

特点: indexOf 方法返回数组中某个指定元素首次出现的位置,利用这一点可以实现去重。

const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  if (uniqueArr.indexOf(arr[i]) === -1) {
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • indexOf 会返回元素在数组中第一次出现的索引,如果返回 -1 表示该元素还未在 uniqueArr 中存在。
  • 如果元素不存在于 uniqueArr 中,则将其推入 uniqueArr

2.特殊数组

特点:

  • indexOfNaN 无法正确判断,不能去重。
  • undefined 可以去重。
  • 数组和对象无法去重,因为 indexOf 也是基于引用比较。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaN 未被去重。
  • undefined 被去重。
  • 数组和对象未被去重。

方法四:利用sort()

1.普通数组

特点: 通过对数组进行排序,然后遍历数组,相邻元素比较是否相同来去重。

const arr = [1, 2, 3, 3, 4, 5, 5];
arr.sort();
const uniqueArr = [arr[0]];
for (let i = 1; i < arr.length; i++) {
  if (arr[i] !== arr[i - 1]) {
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • 先使用 sort() 对数组进行排序,使得相同元素相邻。
  • 然后从第二个元素开始,依次与前一个元素比较,不相同则加入 uniqueArr

2.特殊数组

特点:

  • sort() 排序不能正确处理 NaN,但可以通过比较去重。
  • undefined 可以去重。
  • 数组和对象按引用比较,无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaN 未被去重。
  • undefined 被去重。
  • 数组和对象未被去重。

方法五:利用对象的属性不能相同的特点进行去重

1.普通数组

特点: 对象的属性名是唯一的,可以利用这一点来去重。

const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  if (!uniqueObj[arr[i]]) {
    uniqueObj[arr[i]] = true;
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • 遍历数组时,利用元素的值作为对象的键,如果对象中不存在该键,则添加它并推入 uniqueArr
  • 这种方法适用于基本类型的数组,不适用于复杂类型(如对象数组)。

2.特殊数组

特点:

  • NaNundefined 都可以被正确去重。
  • 数组和对象无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  const key = typeof arr[i] + JSON.stringify(arr[i]);
  if (!uniqueObj[key]) {
    uniqueObj[key] = true;
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaNundefined 被去重。
  • 数组和对象未被去重。

方法六:利用includes

1.普通数组

特点: includes 方法用于判断一个数组是否包含某个指定的值。

const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  if (!uniqueArr.includes(arr[i])) {
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • includes 返回布尔值,如果数组中不存在该元素,则 pushuniqueArr

2.特殊数组

特点:

  • includes 不能正确判断 NaN,因此无法去重。
  • undefined 可以去重。
  • 数组和对象无法去重,因为 includes 也是基于引用比较。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaN 未被去重。
  • undefined 被去重。
  • 数组和对象未被去重。

方法七:利用hasOwnProperty

1.普通数组

特点: 类似于方法五,使用对象的属性名作为唯一标识进行去重。

const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  if (!uniqueObj.hasOwnProperty(arr[i])) {
    uniqueObj[arr[i]] = true;
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • hasOwnProperty 用于检查对象是否包含特定属性,这样可以避免属性被 undefined 覆盖。

2.特殊数组

特点:

  • NaNundefined 可以被去重。
  • 数组和对象无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
const uniqueObj = {};
const uniqueArr = [];
for (let i = 0; i < arr.length; i++) {
  const key = typeof arr[i] + JSON.stringify(arr[i]);
  if (!uniqueObj.hasOwnProperty(key)) {
    uniqueObj[key] = true;
    uniqueArr.push(arr[i]);
  }
}
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaNundefined 被去重。
  • 数组和对象未被去重。

方法八:利用递归去重

1.普通数组

特点: 通过递归函数进行去重,可以处理嵌套数组或多层嵌套的情况。

const arr = [1, 2, 3, 3, 4, 5, 5];
function unique(arr) {
  if (arr.length === 0) return [];
  const [first, ...rest] = arr;
  return rest.includes(first) ? unique(rest) : [first, ...unique(rest)];
}
console.log(unique(arr)); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • 递归将数组拆分为头部和尾部,然后检查头部是否在尾部存在,如果存在则递归处理尾部数组。

2.特殊数组

特点:

  • NaN 不能去重。
  • undefined 可以去重。
  • 数组和对象的引用不同,无法去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(unique(arr)); // 输出: [NaN, NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaN 未被去重。
  • undefined 被去重。
  • 数组和对象未被去重。

方法九:利用Map数据结构去重

1.普通数组

特点: Map 对象允许键值对,并且键是唯一的,利用这一特性可以去重。

const arr = [1, 2, 3, 3, 4, 5, 5];
const map = new Map();
const uniqueArr = arr.filter(item => !map.has(item) && map.set(item, 1));
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • 通过 filter 遍历数组,同时检查 Map 是否已有该值,没有则添加到 Map 并保留该元素。

2.特殊数组

特点:

  • NaNundefined 都可以被去重。
  • 数组和对象可以通过引用来去重。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, undefined, [1], [1], {a: 1}, {a: 1}]

结果:

  • NaNundefined 被去重。
  • 数组和对象未被去重。

方法十:利用reduce+includes

1.普通数组

特点: reduce 可以累积操作结果,通过 includes 检查是否已存在该元素。

const arr = [1, 2, 3, 3, 4, 5, 5];
const uniqueArr = arr.reduce((acc, curr) => {
  if (!acc.includes(curr)) acc.push(curr);
  return acc;
}, []);
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5]

详细说明:

  • reduce 会遍历数组并累积结果,如果当前元素不在累积数组中,则添加进去。

2.特殊数组

特点:

  • NaN 不能去重。
  • undefined 可以去重。
  • 数组和对象无法去重,因为 includes 也是基于引用比较。
const arr = [NaN, NaN, undefined, undefined, [1], [1], {a: 1}, {a: 1}];
console.log(uniqueArr); // 输出: [NaN, NaN, undefined, , [1], [1], {a: 1}, {a: 1}]

方法十一:利用filter

1.普通数组

特点: filter 的主要作用是通过一个回调函数,过滤掉不符合条件的数组元素。通过结合 indexOfincludesmap 或者其他逻辑判断,可以实现数组去重。

const arr = [1, 2, 2, 3, 4, 4, 5, 'a', 'b', 'a'];
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArr); // 输出: [1, 2, 3, 4, 5, 'a', 'b']

详细说明:

  • arr.indexOf(item) 会返回数组中第一次出现该元素的索引。
  • 如果当前元素的索引与 indexOf 返回的索引相同,说明该元素是第一次出现,保留它。
  • 如果不同,则该元素是重复的,过滤掉。

2.特殊数组

特点:

  • NaN 是一个特殊的值,NaN !== NaN,所以 indexOfincludes 无法正确识别 NaN
  • undefined 可以通过 indexOfincludes 进行正常识别,因为 undefined === undefinedtrue
  • 数组属于引用类型,indexOfincludes 对于数组只进行引用比较,而不是值比较。
  • 对象也是引用类型,同样,indexOfincludes 对对象进行引用比较,而不是值比较。

去重方法:

const arr = [NaN, 1, NaN, 2, 2];
const uniqueArr = arr.filter((item, index) => {
  return item !== item ? arr.findIndex(isNaN) === index : arr.indexOf(item) === index;
});
console.log(uniqueArr); // 输出: [NaN, 1, 2]

说明:

  • 使用 item !== item 来判断是否为 NaN,因为只有 NaN !== NaNtrue
  • 对于 NaN,利用 findIndex(isNaN) 查找第一个 NaN 的索引。

去重方法:

const arr = [undefined, 1, undefined, 2, 2];
const uniqueArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(uniqueArr); // 输出: [undefined, 1, 2]

说明:

  • undefined 的去重处理与普通基本类型数据(如数字、字符串等)相同。

去重方法:

const arr = [[1, 2], [1, 2], [3, 4], {a: 1}, {a: 1}, {b: 2}];
const uniqueArr = arr.filter((item, index) => {
  return arr.findIndex(i => JSON.stringify(i) === JSON.stringify(item)) === index;
});
console.log(uniqueArr); // 输出: [[1, 2], [3, 4], {a: 1}, {b: 2}]

说明:

  • 通过 JSON.stringify 将数组序列化为字符串进行比较,从而实现值比较去重。
  • findIndex 返回第一个与当前序列化后的字符串相同的索引,来判断是否保留该数组元素。
  • 该方法可以识别对象属性和值是否相同,从而实现对象去重。