recorrer objetos objeto lista hacer eliminar elemento convertir buscar array agregar javascript object data-structures set

lista - Conjunto de objetos en javascript



lista de objetos javascript (8)

Aquí hay una sugerencia enojada ... clave en el resultado de JSON.stringify(object)

Me gustaría tener un conjunto de objetos en Javascript. Es decir, una estructura de datos que contiene solo objetos únicos.

Normalmente se recomienda el uso de propiedades, por ejemplo, myset["key"] = true . Sin embargo, necesito que las llaves sean objetos. He leído que Javascript arroja nombres de propiedad a cadenas, así que supongo que no puedo usar myset[myobject] = true .

Podría usar una matriz, pero necesito algo mejor que el rendimiento O (n) para agregar, encontrar y eliminar elementos.

Necesita poder diferenciar los objetos solo por referencia, por lo tanto, dado:

var a = {}; var b = {};

entonces tanto a como b deberían poder agregarse, porque son objetos separados.

Básicamente, busco algo como el std::set C ++, que pueda almacenar objetos Javascript. ¿Algunas ideas?


ES6 proporciona un Set nativo:

let s = new Set(); let a = {}; let b = {}; s.add(a); console.log(s.has(a)); // true console.log(s.has(b)); // false


Estoy respondiendo mi propia pregunta, pero se me ocurrió una solución alternativa que pensé que era interesante y pensé que sería útil compartirla.

La respuesta de los lobos me dio una idea. Si el método toString() de un objeto identifica de manera única la instancia, las propiedades de un objeto se pueden usar para almacenar un conjunto de objetos. Básicamente, para almacenar el objeto x , puede usar items[x.toString()] = x; . Tenga en cuenta que el valor es el objeto en sí, de modo que el conjunto de objetos se puede extraer mirando todas las propiedades del elemento y volcando todos los valores en una matriz.

Aquí está la clase, a la que llamo ObjectSet , en su totalidad. Requiere que los objetos se identifiquen de manera única por su método toString() , lo cual está bien para mis propósitos. add , remove y contains deberían ejecutarse en un tiempo mejor que O (n) - sea cual sea la eficacia de acceso a la propiedad de javascript, que ojalá sea O (1) u O (n log n).

// Set of objects. Requires a .toString() overload to distinguish objects. var ObjectSet = function () { this.items = {}; this.item_count = 0; }; ObjectSet.prototype.contains = function (x) { return this.items.hasOwnProperty(x.toString()); }; ObjectSet.prototype.add = function (x) { if (!this.contains(x)) { this.items[x.toString()] = x; this.item_count++; } return this; }; ObjectSet.prototype.remove = function (x) { if (this.contains(x)) { delete this.items[x.toString()]; this.item_count--; } return this; }; ObjectSet.prototype.clear = function () { this.items = {}; this.item_count = 0; return this; }; ObjectSet.prototype.isEmpty = function () { return this.item_count === 0; }; ObjectSet.prototype.count = function () { return this.item_count; }; ObjectSet.prototype.values = function () { var i, ret = []; for (i in this.items) { if (this.items.hasOwnProperty(i)) ret.push(this.items[i]); } return ret; };


No es posible para todos los objetos, pero si su objeto tiene implementado un método .toString() , es:

var x = {toString: function(){ return ''foo''; }}; var y = {toString: function(){ return ''bar''; }}; var obj = {}; obj[x] = ''X''; obj[y] = ''Y''; console.log(obj); // { foo: ''X'', bar: ''Y'' }

Si quiere que esto sea más fácil, conviértalo en una clase:

function myObj(name){ this.name = name; } myObj.prototype.toString = function(){ return this.name; } var obj = {}; obj[new myObj(''foo'')] = ''X''; obj[new myObj(''bar'')] = ''Y'';


Parece que la llamada interna de la función funciona cuando se le agrega el prefijo. Ejemplo:

var put; this.put = put = function(x) { if (!this.contains(x)) list.push(x); return this; }


Por lo que intenta hacer (conjuntos de objetos), no hay una implementación nativa de Javascript. Tendría que implementar esto por su cuenta. Una forma de hacerlo sería implementar una función hash para sus objetos. El tipo de datos de respaldo del conjunto sería una matriz asociativa, donde la clave de la matriz es el valor que obtienes al invocar la función hash del objeto, y el valor de la matriz es el objeto mismo.

Por supuesto, esto no aborda el problema que usted destacó, por lo que deberá tener en cuenta la igualdad también (¿implementar una función igual quizás)?

En lugar de hacer que la función hash sea una propiedad del objeto en sí, puede tener una función hash independiente que toma un objeto como entrada y genera un valor hash (presumiblemente al iterar sobre sus propiedades).

Al usar este método, usted debería poder obtener O(1) para insertar, buscar y eliminar (sin contar el orden de la función hash, que no debería ser peor que O(n) , especialmente si está iterando sobre su propiedades para crear su valor hash).


Simplemente tecleé esto, solo se prueba brevemente:

var Set = function Set() { var list = []; var contains; this.contains = contains = function(x) { return list.indexOf(x) >= 0; } var put; this.put = put = function(x) { if (!contains(x)) list.push(x); return this; } var remove; this.remove = remove = function(x) { var idx = list.indexOf(x); if (idx >= 0) list.splice(idx,1); return this; } var all; this.all = all = function() { return list.concat(); } return this; }


ECMAScript6 Set debería comportarse así:

Ejemplo de trabajo en Firefox 32 (pero no implementado en Chromium 37):

if (Set) { var s = new Set() var a = {} var b = {} var c = {} s.add(a) s.add(b) s.add(b) assert(s.size === 2) assert(s.has(a)) assert(s.has(b)) assert(!s.has(c)) }

Esto no es sorprendente ya que {} != {} : Igualdad compara direcciones de objeto de forma predeterminada.

Un módulo que lo implementa para navegadores sin soporte: https://github.com/medikoo/es6-set