javaScript中的对象比较是线性时间还是常数时间?

Posted

技术标签:

【中文标题】javaScript中的对象比较是线性时间还是常数时间?【英文标题】:Is object comparison in javaScript in linear or constant time? 【发布时间】:2022-01-12 05:56:18 【问题描述】:

我想知道,当 javascript 比较 2 个对象时,是否必须递归遍历每个键以确定严格相等 (O(log(2n))?如果您在 JavaScript 中比较字符串,是否必须通过以下方式比较它们?每个字母或二进制信息的总和是否足以进行 1 对 1 比较 O(1)?比较 JSON 对象或 javascript 对象是否更快?

感谢任何部分的任何答案或更正我的原始组合。

【问题讨论】:

见specification。 “JSON 对象”不是一种存在的语言结构,更不用说能够比某些东西更快地进行比较了。唯一按结构比较的东西是Records and Tuples,一旦它们成为标准的一部分。 如果你的意思是obj1 === obj2 那么不,比较参考是 O(1)。 您是在谈论对象、字符串还是两者兼而有之? 如何获得遍历所有键的对数复杂度? n 是什么? “JSON 对象”是什么意思,它与 javascript 对象有何不同? 【参考方案1】:

在 JS 中,对象通过引用进行比较(不是结构/深度相等)。因为只比较固定长度的内存地址,所以比较是 O(1)。

例如,即使obj1obj2 中的每个键/值对都相同,下面的代码 sn-p 始终会输出 false。 obj1obj2 不引用同一个底层对象,对象是通过引用进行比较,而不是键和值。

let obj1 =  a: 1, b: 2 ;
let obj2 =  a: 1, b: 2 ;
console.log(obj1 == obj2 || obj1 === obj2); // => false

然而,这段代码打印的是 true,因为在这种情况下 obj1obj2 确实指的是同一个对象。

obj1 =  a: 1, b: 2 ;
obj2 = obj1;
console.log(obj1 == obj2 && obj1 === obj2); // => true

如果您想比较两个对象的结构和内容,而不仅仅是评估引用相等性,您可以使用 Node 的 assert.deepEqual(),它在要比较的键/值对总数中是线性的。

要比较浏览器中的任意对象,您可以使用JSON.stringify(obj1) === JSON.stringify(obj2)。这在被比较的键/值对的数量上也大致呈线性关系,但它取决于键/值对的字符串化版本的长度,而不仅仅是键/值对的数量。你可以说它是 O(nm),其中 n 是 k/v 对的数量,m 是对象中 k/v 对的平均字符串长度,因此 nm 是字符串 JSON.stringify 的总长度产生。 (m 可能只是一个小常数,但如果没有先验知识限制它,它很可能会超过 n,因此您必须将其考虑在内)

通常,assert.deepEqual() 在最好的情况下会更快,因为它可以更早地返回:只要正在比较的键/值对不匹配,断言就会失败并提前返回。如果前 k/v 对不匹配,assert.deepEqual() 可能会在 O(1) 中返回。然而,在最坏的情况下,比较相等的对象,它是 O(n)。

使用 JSON.stringify,必须在比较开始之前将整个对象转换为字符串,因此它是 O(nm) 最好和最坏的情况。当然,您也可以实现自己的递归 deepEquals 方法来实现与 assert.deepEqual() 相同的性能,或者使用 lodash.isEqual(),它们只是不是原生的。

解决您的另一个问题,字符串不能在 O(1) 中通过“其二进制信息的总和”进行比较。两个不同的字符串可以求和为相同的值,并且确定该和在二进制表示中的位数仍然是线性的。长度为 n 的字符串的二进制表示中的位数为 O(n),因为每个字符都由固定位数表示。相反,如果您的意思是逐位比较字符串(这本质上是标准字符串比较中发生的情况),出于同样的原因,这仍然是 O(n)。

我认为您可能将固定大小整数的 O(1) 比较复杂性与字符串比较的复杂性混为一谈。相关的区别在于,当整数存储在内存的单个机器字中时(例如在 64 位机器上比较两个 interned,但这不会帮助您比较 JSON.stringified 对象,因为您仍然需要执行这两个 O( nm) 预先进行字符串化。

【讨论】:

好答案,但我不会说m 通常是一个常数,因为它包含对象中任意的 values 的字符串大小(并且可能甚至比所有对象键加起来还要大)。 @Bergi 非常正确,我编辑了我的答案

以上是关于javaScript中的对象比较是线性时间还是常数时间?的主要内容,如果未能解决你的问题,请参考以下文章

如何从javascript中的一个线性箭头函数返回匿名对象? [复制]

1.线性表

Scipy---1.常数和特殊函数

JavaScript中的对象比较[重复]

javascript 对象中的元素数

将对象推入javascript深拷贝还是浅拷贝中的数组?