【问题标题】:Javascript Array lookup efficiency: associative vs. stored associative?Javascript数组查找效率:关联与存储关联?
【发布时间】:2011-08-18 19:42:13
【问题描述】:

我一直在阅读,他们说关联数组不会为您提供与数组相同的效率。关联数组可以在 O(N) 时间内查找,而数组可以在 O(1) 时间内查找。

这是我的问题:在快速查找值和不占用太多内存方面,哪一个效率更高?

联想:

var myVars=new Array(); 
myVars['test1'] = a;
myVars['test2'] = b;
myVars['test3'] = c;
... (up to 200+ values)

echo myVars['test2'];

存储关联:

var myVars=new Array(); 
var TEST1 = 1;
var TEST2 = 2;
var TEST3 = 3;
... (up to 200+ values)

myVars[TEST1] = a;
myVars[TEST2] = b;
myVars[TEST3] = c;
... (up to 200+ values)

echo myVars[TEST2];

【问题讨论】:

标签: javascript arrays performance


【解决方案1】:

首先,Array的第一次使用是错误的。虽然可能这样做,但这并不意味着你应该这样做。您“滥用”了数组也是对象的事实。这可能导致意外行为,例如尽管您添加了 200 个值,但 myVars.length 将是 0

不要将 JavaScript 数组用作关联数组。为此使用普通对象:

var myVars = {}; 
myVars['test1'] = a;
myVars['test2'] = b;
myVars['test3'] = c;

其次,在 JavaScript 中,两者(对象和数组)之间没有真正的区别。数组扩展对象并添加一些行为,但它们仍然是对象。元素存储为数组的属性。

您可以在specification找到更多信息:

数组对象对特定类别的属性名称给予特殊处理。当且仅当 ToString(ToUint32(P)) 等于 P 且 ToUint32(P) 不等于 232 时,属性名称 P(以字符串值的形式)是数组索引-1。 (...)

两者兼有:

var obj = {'answer': 42};
obj['answer'];

var arr = [42];
arr[0];

具有相同的访问时间,这绝对是O(n)

†:最好说应该。显然,这在不同的实现中有所不同。


除此之外,您的第二个示例很难维护。如果给变量赋值,为什么不直接使用数字呢?

var myVars = []; 
myVars[0] = a;
myVars[1] = b;
myVars[2] = c;

更新:

更重要的是:您必须根据需要选择正确的数据结构,这不仅取决于单个元素的访问时间,还取决于:

  • 键是连续数字还是任意字符串/数字?
  • 您是否必须访问集合的所有(即遍历所有)元素?

数值数组(数组)和关联数组(或哈希表/映射(JS中的对象))针对不同的问题提供不同的解决方案。

【讨论】:

  • 确定这是错的吗?我不是 JavaScript 程序员,但我的理解是 JavaScript ArrayObject 的一种类型,因此可以像任何其他对象一样使用。这样做会令人困惑,但在技术上并非不正确。
  • @btilly:这是错误的,因为它令人困惑。我不是说技术上的错误。例如。如果您以这种方式分配值,arr.length 仍将是 0。将澄清我的答案...
  • @btilly 直到你想遍历你的哈希并最终得到 Array 的所有方法。当然,你也可以解决这个问题,但是当有一个更清洁、更常见的地方容器时,这是不必要的工作。
  • 对不起,我应该解释得更好。我有不止一个这样的存储设备,并且为每一个都有一个查找表会相当烦人。理想情况下,我更愿意在我的代码中看到 myVars['test1'] 而不是 myVars[23],尤其是当我要查看多个 myVar 时。
  • 我同意更新。但是,这是一个性能测试:jsperf.com/javascript-associative-vs-non-associative-arrays
【解决方案2】:

首先,不管他们是谁,请随意忽略他们。

每一种体面的脚本语言的每一种体面的实现,包括 JavaScript,都会给你一个关联数组,要么是 O(log(n)) 访问时间,要么是 O(1) 平均访问时间,O(n) 最坏情况 (你几乎从来没有碰到过)。无论哪种方式,在实践中查找都很快。

数组有 O(1) 保证的访问时间,这非常快。但在某些脚本语言(例如 PHP)中,甚至没有提供原生数组类型。他们只是对两者都使用关联数组。

【讨论】:

  • Javascript 也没有正确的数组,它们是伪造的。当前数组实现中的查找与对象属性查找所用的时间相同。
  • @Alnitak:JavaScript 数组支持移位。这向我表明,在底层有 2 种不同的查找机制,因为使用关联数组支持移位会很痛苦。
  • 痛苦的 - 大多数实现必须在你这样做时重新编号所有现有的键!
  • 查看jsperf.com/pop-vs-shift-on-a-array/6(不是我的)来比较流行与移位。在较旧的浏览器上,预先准备的速度要慢 1000 倍。只有 Chrome 和 IE9.0 在数组上具有 O(1) 类型的性能。
【解决方案3】:

答案:test it out yourself

更新:在与 Felix 反复讨论之后,似乎数组访问通常比关联数组和对象都快。情况并非总是如此,尤其是在 Chrome 中。在 Ubuntu 11 上的 Chrome 11 中,阵列速度更快。在 Mac OS 10.6 上的 Chrome 11 中,它们之间没有显着差异。

这些测试没有衡量操纵,只衡量阅读。

【讨论】:

  • Chrome 中似乎有一些字符串包含数字作为对象属性。如果您使用“普通”字符串,则两者显示相同的性能:jsperf.com/object-vs-array-perf
  • @LeviMorrison:你必须小心。您仍在使用数组 [] 作为“关联数组”。您应该改用对象。根据规范,我假设每当在数组上设置属性时,都会检查该属性是否为数字,这会产生开销。使用对象时比较结果:jsperf.com/javascript-associative-vs-non-associative-arrays/3
  • @Felix:说实话,你才是需要小心的人。我理解您的担忧,但最终我正在测试作者的要求。如果他愿意换成真实的对象,那我也愿意。我回答了被问到的问题。 :)
  • @Felix:另外,我确实比较了jsperf.com/javascript-associative-vs-non-associative-arrays/3 上的结果,在 Firefox 中,我们得到了有利于数组的巨大性能差异。
  • @LeviMorrison:我想在这里我们可以再次看到浏览器实现的不同之处。是的,你是对的,你从字面上回答了这个问题。但我假设 OP 不知道不应该以这种方式使用数组。并且只表明一种方式更慢会让他相信他不能在 JS 中拥有像关联数组这样的东西。海事组织最好澄清这种误解。但无论如何,你的测试用例很有趣。
【解决方案4】:

我认为目前的回应并未充分考虑更实际的用例。我创建了this jsperf to demonstrate。虽然@Felix 的jsperf demonstrates lookup speed,它并没有在足够大的对象上执行以使其真正有用。我认为10,000个简单的属性更合理。此外,还需要在序列中随机选择keys进行读取、修改、删除和创建,以真实展示两种类型的性能差异。

【讨论】:

    猜你喜欢
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    • 2015-06-13
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    相关资源
    最近更新 更多