整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

面试官:小伙子,你的数组去重方式惊艳到我了

面试官:小伙子,你的数组去重方式惊艳到我了

题开始,数组去重,即从一个数组中移除所有重复的元素,确保每个元素只出现一次,是这一类问题的核心。

使用原生 JavaScript 方法

1. filter() 方法配合 indexOf()

const uniqueArray=array.filter((item, index, self)=> {
  return self.indexOf(item)===index;
});

该方法利用 filter() 遍历数组,对于每个元素,通过 indexOf() 查找其在原数组中的第一个索引。如果当前元素的索引与正在遍历的索引相同,说明这是该元素在数组中的首次出现,保留该元素;否则,忽略该元素。

2. reduce() 方法

const uniqueArray=array.reduce((acc, current)=> {
  return acc.includes(current) ? acc : [...acc, current];
}, []);

这里使用 reduce() 函数将数组累积到一个新的数组(acc)中。在每次迭代中,检查当前元素是否已存在于累积数组中。若不存在,则将其添加至累积数组;否则,跳过该元素。

利用 ES6 新特性

1. 使用扩展运算符与解构赋值

const uniqueArray=[...new Set(array)];

这种方法简洁高效,利用 ES6 的 Set 数据结构自动去除重复元素的特性,再通过扩展运算符将 Set 转换回数组。Set 是一种特殊的集合,不允许重复元素存在,因此插入过程会自动过滤重复项。

2. 利用 Map 数据结构

const uniqueArray=Array.from(new Map(array.map(item=> [item, item])).values());

尽管不如直接使用 Set 直观,但此方法同样有效。它首先将数组映射为键值对相同的 Map,由于 Map 键的唯一性,重复的数组元素会被自动忽略。然后通过 Array.from()Map.values()Map 的值(即无重复元素)转换回数组。

双重循环与哈希表

1. 双重循环

const uniqueArray=[];
for (let i=0; i < array.length; i++) {
  let isDuplicate=false;
  for (let j=0; j < i; j++) {
    if (array[i]===array[j]) {
      isDuplicate=true;
      break;
    }
  }
  if (!isDuplicate) {
    uniqueArray.push(array[i]);
  }
}

这种方法最直观也最基础,通过外层循环遍历数组,内层循环检查当前元素是否与之前的所有元素重复。如果没有重复,则将其添加到结果数组中。虽然理解简单,但时间复杂度较高,不适用于大型数据集。

2. 利用对象作为哈希表

const uniqueArray=[];
const hashTable={};
for (let i=0; i < array.length; i++) {
  const item=array[i];
  if (!hashTable[item]) {
    uniqueArray.push(item);
    hashTable[item]=true;
  }
}

这种方法利用对象作为哈希表,以数组元素作为键。在遍历过程中,若元素尚未作为对象的键存在,则添加到结果数组并将其设置为哈希表的键。由于对象属性查找的时间复杂度接近 O(1),这种方法在处理大量数据时比双重循环更为高效。

性能比较与优化策略

1. 性能比较

  • filter() + indexOf():线性时间复杂度 O(n^2),适合小型数据集。
  • reduce():线性时间复杂度 O(n^2),适合小型数据集。
  • 扩展运算符与 Set:近乎线性时间复杂度 O(n),非常高效,适合各种规模的数据集。
  • Map:近乎线性时间复杂度 O(n),非常高效,适合各种规模的数据集。
  • 双重循环:平方时间复杂度 O(n^2),效率低,仅适用于极小数据集。
  • 哈希表:近乎线性时间复杂度 O(n),高效,适合各种规模的数据集。

2. 优化策略

  • 选择合适的方法:根据数据规模和项目需求,优先考虑使用 SetMap 或哈希表方法,它们具有更高的时间效率。
  • 预处理数据:如果可能,提前对数据进行排序或转换,简化去重逻辑,提高效率。
  • 懒加载与分批处理:对于超大规模数据,可采用懒加载或分批处理策略,避免一次性加载全部数据导致的性能瓶颈。
  • 使用 Web Worker:对于计算密集型的去重操作,可以考虑使用 Web Worker 进行多线程处理,避免阻塞主线程影响用户体验。

ilter

let arr=["头条", "头条", "头条", "plzbefat", "plzbefat", "plzbefat"];
let arrUnique=arr.filter((v, i, self)=> self.indexOf(v)===i); //过滤掉已经存在的值
console.log(arrUnique);

ES6 set函数(值的集合)

let arr=["头条", "头条", "头条", "plzbefat", "plzbefat", "plzbefat"];
let arrUnique=[...new Set(arr)];//值的集合 不能重复
console.log(arrUnique);

关于set函数:

Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。

已知如下数组:
var arr=[ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组

组实例的 flat(),flatMap()

数组的成员有时还是数组,Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。

上面代码中,原数组的成员里面有一个数组,flat()方法将子数组的成员取出来,添加在原来的位置。

flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1

上面代码中,flat()的参数为2,表示要“拉平”两层的嵌套数组。

如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

如果原数组有空位,flat()方法会跳过空位

flatMap()方法对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()),然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。

flatMap()方法的参数是一个遍历函数,该函数可以接受三个参数,分别是当前数组成员、当前数组成员的位置(从零开始)、原数组。

然后,我们来看看文章开始的那道题目如何优雅的求解

如果你还有好的方法,欢迎在下面留言,我会补充上去,供大家学习参考

参考文章:

https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/8