数组的性能包括与映射到对象并在 JavaScript 中访问它

Posted

技术标签:

【中文标题】数组的性能包括与映射到对象并在 JavaScript 中访问它【英文标题】:Performance of array includes vs mapping to an Object and accessing it in JavaScript 【发布时间】:2019-04-24 17:19:29 【问题描述】:

根据CS的基础 未排序列表的search 功能必须在 O(n) 时间内发生,而对于 HashMap,直接访问数组将在 O(1) 时间内发生。

那么将数组映射到字典然后直接访问元素是否更高效,或者我应该只使用包含?这个问题专门针对 javascript,因为我相信这将归结为如何实现 includes() 的核心实现细节。

let y = [1,2,3,4,5]
y.includes(3)

或者...

let y = 
          1: true,
          2: true
          3: true
          4: true
          5: true
        
5 in y

【问题讨论】:

提防过早的优化。 @MarkMeyer 完全 :) 我只是对学习感到好奇。 至于includes作品如何从它的polyfill中得到灵感developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 【参考方案1】:

确实,对象查找发生在恒定时间 - O(1) - 所以使用对象属性而不是数组是一种选择,但如果你只是想检查一个值是否包含在集合中,它会更适合使用Set,它是一个(通常是无序的)值的集合,也可以在线性时间内查找。 (如果使用普通对象,除了您不关心的键之外,您还需要有 - 因此,请改用 Set。)

const set = new Set(['foo', 'bar']);
console.log(set.has('foo'));
console.log(set.has('baz'));

当您必须为同一个Set 查找多个值时,这将很有用。但是,向Set 添加项目(就像向对象添加属性一样)是O(N),所以如果您只是要查找单个值,一次,没有任何好处this 也不是对象技术,你也可以只使用数组includes 测试。

【讨论】:

你知道集合是如何实现的吗?我不知道 Sets 有线性时间查找。我从这个假设中的猜测是,它在幕后实现为哈希图,但没有卫星数据。 参见ecma-international.org/ecma-262/6.0/#sec-set-objects - “集合对象必须使用哈希表或其他机制来实现,这些机制平均而言提供的访问时间与集合中的元素数量呈次线性关系。”。一般是O(1) @CertainPerformance 只是想问一下在集合中添加元素是否需要 O(1) 时间。 @amrendersingh 是的,它是 - 添加属性是一种可预测的简单操作(比查看数据结构复杂得多) @CertainPerformance "但是,向 Set 添加项目(就像向对象添加属性一样)是 O(N)" 这里您指的是添加多个元素以迭代设置?【参考方案2】:

2020 年 4 月 29 日更新

正如评论者正确指出的那样,V8 似乎正在优化数组包含调用。 An updated version 分配给一个 var 并使用它会产生更多预期的结果。在这种情况下,对象地址是最快的,其次是 Set has,在遥远的第三个是 Array 包含(在我的系统/浏览器上)。

尽管如此,我确实坚持我最初的观点,即如果进行微优化,则值得测试假设。只需确保您的测试有效;)

原创

嗯。尽管显然期望 Object address 和 Set 的性能应该优于 Array includes,但针对 Chrome 的基准测试表明实现胜过预期。

在我与 Chrome Array 的比赛中,我的表现是最好的。

我也在本地使用 Node 进行了测试,得到了更多预期的结果。在那个 Object address 获胜,紧随其后的是 Set has,然后 Array includes 比两者都略慢。

底线是,如果您要进行微优化(不建议这样做),则值得进行基准测试,而不是假设哪个可能最适合您的特定情况。正如您的问题所暗示的那样,最终归结为实施。所以针对目标平台进行优化是关键。

这是我得到的结果:

节点(12.6.0):

ops for Object address 7804199
ops for Array includes 5200197
ops for Set has        7178483

Chrome (75.0):https://jsbench.me/myjyq4ixs1/1

【讨论】:

您的测试用例包含非常小的项目集,并且您不使用检查结果,所以我敢打赌,JS JIT 只是优化了 array.includes 案例中的访问。如果您使用更大的样本量并使用检查的结果,则 Set has 操作比 Array.includes 快 40-100 倍以上,用于字符串集(在 macOS 上的 Chrome 和 Firefox 上测试)。 jsbench.me/t4k9lk7h7j/1 - 即使这个版本也有问题,因为我们没有测试否定查找(即不在列表中的项目)的速度。 更新版本 3k 数组中的元素 array.includes vs set.has vs obj.prop 从最快到最慢:obj.prop、set.has、array.includes jsbench.me/kwkyix6rpf/1

以上是关于数组的性能包括与映射到对象并在 JavaScript 中访问它的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL纹理映射总结

我正在尝试映射一个数组并在数组中找到对象的索引

JavaScript的面向对象

js 的数组怎么push一个对象. Js数组的操作push,pop,shift,unshift JavaScrip

JavaScrip对象

Hashmap 与数组性能