Estoy trabajando en JavaScript Me gustaría almacenar una lista de valores de cadena únicos y desordenados, con las siguientes propiedades:
- ¿Una forma rápida de preguntar 'está A en la lista'?
- una forma rápida de hacer 'eliminar A de la lista si existe en la lista'
- una forma rápida de hacer 'agregar A a la lista si aún no está presente'.
Lo que realmente quiero es un set. ¿Alguna sugerencia sobre la mejor manera de imitar un conjunto en JavaScript?
Esta pregunta recomienda el uso de un objeto , con las propiedades de almacenamiento de claves y todos los valores establecidos en verdadero: ¿es esa una manera sensata?
javascript
Ricardo
fuente
fuente
Respuestas:
Si está programando en un entorno compatible con ES6 (como node.js, un navegador específico con las capacidades de ES6 que necesita o transpilando el código de ES6 para su entorno), puede usar el
Set
objeto integrado en ES6 . Tiene capacidades muy agradables y se puede usar como está en su entorno.Para muchas cosas simples en un entorno ES5, usar un objeto funciona muy bien. Si
obj
es su objeto yA
es una variable que tiene el valor con el que desea operar en el conjunto, puede hacer lo siguiente:Código de inicialización:
Pregunta 1: está
A
en la lista:Pregunta 2: Eliminar 'A' de la lista si está allí:
Pregunta 3: Agregue 'A' a la lista si aún no estaba allí
Para completar, la prueba de si
A
está en la lista es un poco más segura con esto:debido a un posible conflicto entre los métodos integrados y / o las propiedades en el Objeto base, como la
constructor
propiedad.Barra lateral en ES6: la versión de trabajo actual de ECMAScript 6 o algo llamado ES 2015 tiene un objeto Set incorporado . Se implementa ahora en algunos navegadores. Dado que la disponibilidad del navegador cambia con el tiempo, puede consultar la línea
Set
en esta tabla de compatibilidad de ES6 para ver el estado actual de la disponibilidad del navegador.Una ventaja del objeto Set incorporado es que no obliga a todas las teclas a una cadena como lo hace el Objeto, por lo que puede tener tanto 5 como "5" como teclas separadas. E incluso puede usar objetos directamente en el conjunto sin una conversión de cadena. Aquí hay un artículo que describe algunas de las capacidades y la documentación de MDN sobre el objeto Set.
Ahora he escrito un polyfill para el objeto de conjunto ES6 para que pueda comenzar a usarlo ahora y se transferirá automáticamente al objeto de conjunto incorporado si el navegador lo admite. Esto tiene la ventaja de que está escribiendo un código compatible con ES6 que funcionará desde IE7. Pero, hay algunas desventajas. La interfaz del conjunto ES6 aprovecha los iteradores ES6 para que pueda hacer cosas como
for (item of mySet)
y automáticamente iterará a través del conjunto por usted. Pero, este tipo de función de lenguaje no se puede implementar a través de polyfill. Todavía puede iterar un conjunto ES6 sin usar las nuevas funciones de idiomas ES6, pero, francamente, sin las nuevas funciones de idioma, no es tan conveniente como la otra interfaz de conjunto que incluyo a continuación.Puedes decidir cuál funciona mejor para ti después de mirar a ambos. El polyfill del conjunto ES6 está aquí: https://github.com/jfriend00/ES6-Set .
Para su información, en mis propias pruebas, me di cuenta de que la implementación de Firefox v29 Set no está completamente actualizada en el borrador actual de la especificación. Por ejemplo, no puede encadenar
.add()
llamadas de método como lo describe la especificación y mi polyfill admite. Probablemente se trate de una especificación en movimiento, ya que aún no está finalizada.Objetos de conjunto preconstruido: si desea un objeto ya construido que tenga métodos para operar en un conjunto que pueda usar en cualquier navegador, puede usar una serie de diferentes objetos preconstruidos que implementan diferentes tipos de conjuntos. Hay un miniSet que es un código pequeño que implementa los conceptos básicos de un objeto establecido. También tiene un objeto de conjunto más rico en funciones y varias derivaciones que incluyen un Diccionario (le permite almacenar / recuperar un valor para cada clave) y un ObjectSet (le permite mantener un conjunto de objetos, ya sea objetos JS u objetos DOM donde puede suministrar el función que genera una clave única para cada uno o el ObjectSet generará la clave para usted).
Aquí hay una copia del código para el miniSet (el código más actualizado es aquí en github ).
fuente
Object.keys(obj)
.Object.keys()
necesita IE9, FF4, Safari 5, Opera 12 o superior. Hay un polyfill para navegadores antiguos aquí .obj.hasOwnProperty(prop)
para cheques de membresía. Use en suObject.prototype.hasOwnProperty.call(obj, prop)
lugar, lo que funciona incluso si el "conjunto" contiene el valor"hasOwnProperty"
.Puede crear un objeto sin propiedades como
que puede actuar como un conjunto y elimina la necesidad de usar
hasOwnProperty
.fuente
set = {}
, heredará todas las propiedades de Object (por ejemplotoString
), por lo que tendrá que verificar la carga útil del conjunto (propiedades que agregó)hasOwnProperty
enif (A in set)
set[A]=true
declaraciones para cada elemento que desee agregar en lugar de solo un inicializador?s = Object.create(null);s["thorben"] = true;ss = Object.create(s)
A partir de ECMAScript 6, la estructura de datos Set es una característica incorporada . La compatibilidad con las versiones de node.js se puede encontrar aquí .
fuente
in
no funciona porque losSet
objetos no tienen sus elementos como propiedades, lo que sería malo porque los conjuntos pueden tener elementos de cualquier tipo, pero las propiedades son cadenas. Puedes usarhas
:Set([1,2]).has(1)
En la versión ES6 de Javascript, ha incorporado el tipo de conjunto ( verifique la compatibilidad con su navegador ).
Para agregar un elemento al conjunto que simplemente usa
.add()
, que se ejecutaO(1)
y agrega el elemento al conjunto (si no existe) o no hace nada si ya está allí. Puede agregar elementos de cualquier tipo allí (matrices, cadenas, números)Para verificar el número de elementos en el conjunto, simplemente puede usar
.size
. También corre enO(1)
Para eliminar el elemento del conjunto, use
.delete()
. Devuelve verdadero si el valor estaba allí (y fue eliminado), y falso si el valor no existía. También corre enO(1)
.Para verificar si el elemento existe en un conjunto de uso
.has()
, que devuelve verdadero si el elemento está en el conjunto y falso en caso contrario. También corre enO(1)
.Además de los métodos que desea, hay algunos adicionales:
numbers.clear();
simplemente eliminaría todos los elementos del conjuntonumbers.forEach(callback);
iterando a través de los valores del conjunto en orden de inserciónnumbers.entries();
crear un iterador de todos los valoresnumbers.keys();
devuelve las claves del conjunto que es lo mismo quenumbers.values()
También hay un Weakset que permite agregar solo valores de tipo de objeto.
fuente
.add()
ejecuciones en O (1)? Estoy intrigado por esto,He comenzado una implementación de Sets que actualmente funciona bastante bien con números y cadenas. Mi enfoque principal era la operación de diferencia, así que traté de hacerlo lo más eficiente posible. Tenedores y revisiones de código son bienvenidos!
https://github.com/mcrisc/SetJS
fuente
Acabo de notar que la biblioteca d3.js tiene implementación de conjuntos, mapas y otras estructuras de datos. No puedo discutir sobre su eficiencia, pero a juzgar por el hecho de que es una biblioteca popular, debe ser lo que necesita.
La documentación está aquí
Por conveniencia, copio desde el enlace (las 3 primeras funciones son las de interés)
Construye un nuevo conjunto. Si se especifica la matriz, agrega la matriz dada de valores de cadena al conjunto devuelto.
Devuelve verdadero si y solo si este conjunto tiene una entrada para la cadena de valor especificada.
Agrega la cadena de valor especificada a este conjunto.
Si el conjunto contiene la cadena de valor especificada, la elimina y devuelve verdadero. De lo contrario, este método no hace nada y devuelve falso.
Devuelve una matriz de los valores de cadena en este conjunto. El orden de los valores devueltos es arbitrario. Se puede utilizar como una forma conveniente de calcular los valores únicos para un conjunto de cadenas. Por ejemplo:
d3.set (["foo", "bar", "foo", "baz"]). values (); // "foo", "bar", "baz"
Llama a la función especificada para cada valor en este conjunto, pasando el valor como argumento. El contexto de esta función es este conjunto. Devuelve indefinido. El orden de iteración es arbitrario.
Devuelve verdadero si y solo si este conjunto tiene valores cero.
Devuelve el número de valores en este conjunto.
fuente
Sí, esa es una forma sensata, eso es todo lo que es un objeto (bueno, para este caso de uso), un conjunto de claves / valores con acceso directo.
Debería verificar si ya está allí antes de agregarlo, o si solo necesita indicar presencia, "agregar" nuevamente no cambia nada, simplemente lo coloca nuevamente en el objeto.
fuente