Eficiencia de matriz versus objeto en JavaScript

Resuelto Moshe Shaham asked hace 11 años • 8 respuestas

Tengo un modelo con posiblemente miles de objetos. Me preguntaba cuál sería la forma más eficaz de almacenarlos y recuperar un único objeto una vez que tenga su identificación. Las identificaciones son números largos.

Estas son las 2 opciones en las que estaba pensando. en la opción uno es una matriz simple con un índice incremental. en la opción 2 es una matriz asociativa y tal vez un objeto, si eso hace la diferencia. Mi pregunta es cuál es más eficiente, cuando principalmente necesito recuperar un solo objeto, pero a veces también los recorro y ordeno.

Opción uno con matriz no asociativa:

var a = [{id: 29938, name: 'name1'},
         {id: 32994, name: 'name1'}];
function getObject(id) {
    for (var i=0; i < a.length; i++) {
        if (a[i].id == id) 
            return a[i];
    }
}

Opción dos con matriz asociativa:

var a = [];  // maybe {} makes a difference?
a[29938] = {id: 29938, name: 'name1'};
a[32994] = {id: 32994, name: 'name1'};
function getObject(id) {
    return a[id];
}

Actualizar:

Bien, entiendo que usar una matriz en la segunda opción está fuera de discusión. Entonces, la línea de declaración, la segunda opción realmente debería ser: var a = {};y la única pregunta es: qué funciona mejor al recuperar un objeto con una identificación determinada: una matriz o un objeto donde la identificación es la clave.

y además, ¿cambiará la respuesta si tengo que ordenar la lista muchas veces?

Moshe Shaham avatar Jun 25 '13 17:06 Moshe Shaham
Aceptado

La versión corta: las matrices son en su mayoría más rápidas que los objetos. Pero no existe una solución 100% correcta.

Actualización 2017: prueba y resultados

var a1 = [{id: 29938, name: 'name1'}, {id: 32994, name: 'name1'}];

var a2 = [];
a2[29938] = {id: 29938, name: 'name1'};
a2[32994] = {id: 32994, name: 'name1'};

var o = {};
o['29938'] = {id: 29938, name: 'name1'};
o['32994'] = {id: 32994, name: 'name1'};

for (var f = 0; f < 2000; f++) {
    var newNo = Math.floor(Math.random()*60000+10000);
    if (!o[newNo.toString()]) o[newNo.toString()] = {id: newNo, name: 'test'};
    if (!a2[newNo]) a2[newNo] = {id: newNo, name: 'test' };
    a1.push({id: newNo, name: 'test'});
}

configuración de prueba resultados de la prueba

Publicación original - Explicación

Hay algunos conceptos erróneos en su pregunta.

No hay matrices asociativas en Javascript. Sólo matrices y objetos.

Estas son matrices:

var a1 = [1, 2, 3];
var a2 = ["a", "b", "c"];
var a3 = [];
a3[0] = "a";
a3[1] = "b";
a3[2] = "c";

Esta también es una matriz:

var a3 = [];
a3[29938] = "a";
a3[32994] = "b";

Es básicamente una matriz con agujeros, porque cada matriz tiene indexación continua. Es más lento que las matrices sin agujeros. Pero iterar manualmente a través de la matriz es aún más lento (en su mayoría).

Este es un objeto:

var a3 = {};
a3[29938] = "a";
a3[32994] = "b";

Aquí hay una prueba de rendimiento de tres posibilidades:

Matriz de búsqueda, matriz Holey y prueba de rendimiento de objetos

Una lectura excelente sobre estos temas en Smashing Magazine: Escritura rápida de JavaScript con memoria eficiente

Alp avatar Jun 25 '2013 11:06 Alp

En realidad, no es una cuestión de rendimiento en absoluto, ya que las matrices y los objetos funcionan de manera muy diferente (o al menos se supone que deben hacerlo). Las matrices tienen un índice continuo 0..n, mientras que los objetos asignan claves arbitrarias a valores arbitrarios. Si desea proporcionar claves específicas, la única opción es un objeto. Si no te importan las claves, es una matriz.

Si intenta establecer claves arbitrarias (numéricas) en una matriz, realmente tendrá una pérdida de rendimiento , ya que, desde el punto de vista del comportamiento, la matriz completará todos los índices intermedios:

> foo = [];
  []
> foo[100] = 'a';
  "a"
> foo
  [undefined, undefined, undefined, ..., "a"]

(Tenga en cuenta que la matriz en realidad no contiene 99 undefinedvalores, pero se comportará de esta manera ya que [se supone que está] iterando la matriz en algún momento).

Los literales de ambas opciones deberían dejar muy claro cómo se pueden utilizar:

var arr = ['foo', 'bar', 'baz'];     // no keys, not even the option for it
var obj = { foo : 'bar', baz : 42 }; // associative by its very nature
deceze avatar Jun 25 '2013 10:06 deceze

Con ES6, la forma más eficaz sería utilizar un mapa.

var myMap = new Map();

myMap.set(1, 'myVal');
myMap.set(2, { catName: 'Meow', age: 3 });

myMap.get(1);
myMap.get(2);

Puede utilizar las funciones de ES6 hoy utilizando una cuña ( https://github.com/es-shims/es6-shim ).

El rendimiento variará según el navegador y el escenario. Pero aquí hay un ejemplo donde Maptiene mayor rendimiento: https://jsperf.com/es6-map-vs-object-properties/2


REFERENCIA https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

sandstrom avatar Sep 20 '2015 11:09 sandstrom

En NodeJS, si conoce ID, el bucle a través de la matriz es muy lento en comparación con object[ID].

const uniqueString = require('unique-string');
const obj = {};
const arr = [];
var seeking;

//create data
for(var i=0;i<1000000;i++){
  var getUnique = `${uniqueString()}`;
  if(i===888555) seeking = getUnique;
  arr.push(getUnique);
  obj[getUnique] = true;
}

//retrieve item from array
console.time('arrTimer');
for(var x=0;x<arr.length;x++){
  if(arr[x]===seeking){
    console.log('Array result:');
    console.timeEnd('arrTimer');
    break;
  }
}

//retrieve item from object
console.time('objTimer');
var hasKey = !!obj[seeking];
console.log('Object result:');
console.timeEnd('objTimer');

Y los resultados:

Array result:
arrTimer: 12.857ms
Object result:
objTimer: 0.051ms

Incluso si el ID de búsqueda es el primero en la matriz/objeto:

Array result:
arrTimer: 2.975ms
Object result:
objTimer: 0.068ms
Paweł avatar Nov 02 '2017 10:11 Paweł