玖叶教程网

前端编程开发入门

什么时候用Array,什么时候用Set?

家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

今天将重点对比两个数据结构,即 Array 和 Set,话不多说,直接开始。

1.什么是 Set 和 Array?

到目前为止,每个使用 JS 的人都熟悉 Array,但数组到底是什么?一般来说,数组是一种结构,表示在连续内存中分配的数据块(数字、对象等)。比如:

[1, 2, 3, 2];

那 Set 又是什么?Set(集合) 作为数学概念更为人熟知,它是一种抽象数据类型,它只包含不同的元素/对象,不需要按索引顺序分配。比如:

{
  1, 2, 3;
}

所以从概念上看,Array 和 Set 在技术上是不同的概念。您可能会注意到,这里最大的区别之一是 Array 中的元素可以重复(除非您告诉它不要重复),而在 Set 中,它们不能重复(无论您如何决定)。

此外,Array 被认为是“索引集合(indexed collection)”类型的数据结构,而 Set 被认为是“键控集合(keyed collection)”。

  • 索引集合:是按索引值排序的数据集合
  • 键控集合:是使用键的集合,其包含可按插入顺序迭代的元素

在编程世界中,存储相同的数据集(无重复)可以使用 Array 或 Set 作为结构来存储。 然而,选择正确的结构有助于提供最佳解决方案,这也是我们希望实现的目标。

2.如何构造 Set 和 Array?

2.1 构造 Array

数组非常简单,要在 JS 中声明新数组,可以采用如下方式:

var arr = []; //Empty array
var arr = [1, 2, 3]; //Array which contains 1,2,3

或者使用内置构造函数:

var arr = new Array(); //empty array
var arr = new Array(1, 2, 3); //Array which contains 1,2,3

或者使用 Array.from 方法:

var arr = Array.from('123'); //["1","2","3"]

注意:除非你真的需要,否则不要使用 new Array(),因为:

  • 它比普通的 [] 符号执行的慢得多
  • [] 节省更多的打字时间
  • 您可能最终会犯一些意想不到的错误,例如:
var arr1 = new Array(10);
//arr1[0] = undefined but arr1.length = 10
var arr2 = [10];
// arr2[0] = 10 and arr2.length = 1;
var arr3 = new Array(1, 2, 3);
//[1,2,3]
var arr4 = [1, 2, 3];
//[1,2,3]

2.2 构造 Set

只能通过 Set 内置的构造函数来创建 Set。

var emptySet = new Set();
var exampleSet = new Set([1, 2, 3]);

但是绝对不要这样:

new Set(1);

Set 接收可迭代对象作为其输入参数,并将分别创建 set 对象。因此,可以从一个数组构造一个集合,但是它只会包含来自该数组的不同元素,也就是没有重复元素。当然,也可以使用 Array.from() 方法将集合转换回数组。

var set = new Set([1, 2, 3]);
// {1,2,3}
var arr = Array.from(set);
//[1,2,3]

好的,既然知道如何创建它们,那么它们的功能呢?让我们对 Array/Set 提供的最基本的方法做一个小的比较。

2.2.1 定位/访问一个元素

  • 首先,Set 不支持像 Array 那样通过索引随机访问元素,这意味着:
console.log(set[0]);
//undefined
console.log(arr[0]);
//1
  • 由于 Array 数据存储在连续的内存中,CPU 能够通过预取而更快地访问数据。 因此,与其他类型的抽象数据类型相比,通常访问数组中的元素(例如在 for 循环中)会更快、更高效。
  • 使用 Set.prototype.has(value) VS Array.prototype.indexOf(value) 检查元素是否在 Set 中的语法比 Array 更简单
console.log(set.has(0)); // boolean - false
console.log(arr.indexOf(0)); // -1
console.log(set.has(1)); //true
console.log(arr.indexOf(1)); //0

注意:ES6 确实提供了 Array.prototype.includes() ,它的行为类似于 has(),但是,它没有得到广泛支持,比如 IE 浏览器就是特例。

2.2.2 插入元素

通过使用 Array.prototype.push() 可以在时间复杂度为 O(1)的情况下快速完成向 Array 添加新元素,此时元素将被添加到数组的末尾。

arr.push(4); //[1,2,3,4]

或者也可以使用 Array.prototype.unshift() 在时间复杂度为 O(n)的情况下完成将元素添加到数组的开头,此时 n 是当前数组的长度。

arr.unshift(3); //[3,1,2,3]
arr.unshift(5, 6); //[5,6,3,1,2,3]
  • 在 Set 中,只有一种方法可以添加新元素,即 Set.prototype.add()。 由于 Set 必须维护其集合成员之间的“不同”属性,因此在每次调用 add() 时,Set 都需要检查所有成员以确保没有重复。 通常 add() 将花费 O(n) 的运行时间。 然而,由于哈希表实现方法,Set 中的 add() 可能只需要 O(1)。
set.add(3); //{1,2,3}
set.add(4); //{1,2,3,4}

因此 Set 在添加元素方面几乎和 Array 时间复杂度一致。

2.2.3 移除元素

Array 如此流行的好处之一是因为它提供了许多不同的方法来删除元素,例如:

  • Pop() : 删除并返回最后一个元素,时间复杂度 O(1)
arr.pop(); //return 4, [5,6,1,2,3]
  • Shift() — 删除并返回第一个元素,时间复杂度 O(n)
arr.shift(); //return 5; [6,1,2,3]
  • Splice(index, deleteCount): 从索引开始删除 deleteCount 个元素,时间复杂度最多为 O(n)。
arr.splice(0, 1); //[1,2,3]

在 Set 中可以使用如下方法来移除元素。

  • Delete(element) — 从 Set 中删除特定的给定元素
set.delete(4); //{1,2,3}
  • Clear() — 从 Set 中删除所有元素
set.clear(); //{}

虽然 Array 不支持本地构建的方法来删除特定的元素(除非知道它的索引),但需要一个额外的外部函数的帮助来查找该元素的索引并执行 splice(),而 Set 会更加简单。

此外,与目前仅具有上述最基本功能的 Set 相比,Array 确实提供了更多的原生功能(reduce()、reverse()、sort() 等)。

3.什么时候使用 Array?什么时候 Set?

  • 首先,Set 不同于 Array。它并不是要完全取代 Array,而是提供额外的支持类型来完成 Array 缺失的部分。
  • 由于 Set 只包含不同的元素,如果事先知道数据不会重复,使用 Set 会更加省心
  • Set 的基本操作,如 union()、intersect()、difference() 等可以根据本机内置(built-in)操作轻松有效地实现。 由于 delete() 方法存在,使得两个 Set 的交并操作比数组容易的多
  • Array 适用于保持元素有序以便快速访问,或进行大量修改(删除和添加元素)或任何需要对元素进行直接索引访问的操作(例如,尝试对 Set 而不是 Array 做二分查找,如何获取中间元素)

总的来说,Set 与 Array 相比并没有明显的优势,除非在特定情况下。例如当想要以最小成本维护数据的唯一性,或者同时处理大量不同的数据集时使用最基本的集合操作,无需直接访问元素。否则,Array 应该始终是首选。下一篇文章将重点介绍通过Set来提升程序性能的方案,欢迎大家持续关注~

参考资料

原文作者:Maya Shavin

原文链接:https://medium.com/front-end-weekly/es6-set-vs-array-what-and-when-efc055655e1a

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言