176 votos

Imitando establece en JavaScript?

Estoy trabajando en JavaScript. Me gustaría almacenar una lista de los únicos, desordenada valores, con las siguientes propiedades:

  1. una manera rápida de pedir 'es Una en la lista"?
  2. una forma rápida de hacer " eliminar de la lista si existe en la lista'
  3. una forma rápida de hacer 'añadir a la lista si ya no está presente".

Lo que realmente quiero es un conjunto. Sugerencias para la mejor manera de imitar un juego en JavaScript?

Esta pregunta recomienda el uso de un Objeto, con el almacenamiento de claves de propiedades y los valores de todos los establecido en true: es que de un modo razonable?

Gracias por tu ayuda.

ACTUALIZACIÓN: perdón por no ser más clara, los valores que me gustaría tienda son cadenas.

220voto

jfriend00 Puntos 152127

El uso de un Objeto que funciona muy bien. Si obj es su objeto y A es una variable que tiene el valor que se quiere operar en el conjunto, entonces usted puede hacer estos:

Código de inicialización:

// create empty object
var obj = {};

// or create an object with some items already in it
var obj = {"1":true, "2":true, "3":true, "9":true};

Pregunta 1: Es A en la lista:

if (A in obj) {
    // put code here
}

Pregunta 2: Eliminar 'A' de la lista si es que hay:

delete obj[A];

Pregunta 3: Agregar 'a' a la lista, si no estaba ya allí

obj[A] = true;

La integridad, la prueba si A está en la lista es un poco más seguro con este:

if (Object.prototype.hasOwnProperty.call(obj, A)
    // put code here
}

debido a la posibilidad de conflicto entre incorporado en los métodos y/o propiedades en el Objeto de base como el constructor de la propiedad.


Barra lateral: La actual versión de trabajo de ECMAScript 6 (aún no finalizada) ha incorporado un Conjunto de objetos. Es implementado en Firefox y en Chrome, pero requiere de una especial opción en Chrome, habilitar experimental características. Una de las ventajas de la incorporada en el Conjunto de objetos es que no coaccionar todas las claves para una cadena como la que el Objeto, de modo que usted puede tener 5 y "5" como claves separadas. He aquí un artículo que describe algunas de las capacidades y MDN de la documentación sobre el objeto de Conjunto.

Ahora he escrito un relleno para el ES6 objeto de conjunto de modo que usted puede comenzar a usar ahora y automáticamente se sujetará a la incorporada en el conjunto de objetos si el navegador lo soporta. Esto tiene la ventaja de que usted está escribiendo ES6 compatible de código que va a trabajar todo el camino de regreso a IE7. Pero, hay algunos aspectos negativos. La ES6 set interface tiene la ventaja de la ES6 iteradores para que puedas hacer cosas como for (item of mySet) y automáticamente empezará a recorrer el conjunto para usted. Pero, este tipo de característica del lenguaje no puede ser implementado a través de polyfill. Todavía se puede recorrer en un ES6 sin el uso de la nueva ES6 idiomas características, pero, francamente, sin las nuevas características del lenguaje, no es tan conveniente como el otro conjunto interfaz que se incluyen a continuación.

Usted puede decidir cuál funciona mejor para usted después de mirar a ambos. La ES6 conjunto relleno está aquí: https://github.com/jfriend00/ES6-Set.

FYI, en mis propias pruebas, me he dado cuenta de que el Firefox v29 implementación de Conjunto no está totalmente actualizada en el actual borrador de la especificación. Por ejemplo, usted no puede cadena .add() llamadas a métodos como la especificación describe y mi polyfill apoya. Esta es probablemente una cuestión de una especificación en movimiento, ya que esto aún no está finalizado.


Pre-Construido Conjunto de objetos: Si desea que un objeto ya construido que tiene métodos para el manejo de un conjunto que se puede usar en cualquier navegador, se puede usar una serie de pre-construcción de objetos que implementan diferentes tipos de conjuntos. Hay un miniSet que es pequeño código que implementa los conceptos básicos de un conjunto de objetos. También tiene una característica más rico conjunto de objetos y varias derivaciones, incluyendo un Diccionario (permite almacenar/recuperar un valor para cada tecla) y un ObjectSet (vamos a mantener una serie de objetos - ya sea de objetos JS o de objetos DOM de que usted sea el suministro de la función que genera una clave única para cada uno o el ObjectSet generará la clave para usted).

Aquí está una copia del código para el miniSet (la mayoría hasta la fecha-el código es aquí en github).

"use strict";
//-------------------------------------------
// Simple implementation of a Set in javascript
//
// Supports any element type that can uniquely be identified
//    with its string conversion (e.g. toString() operator).
// This includes strings, numbers, dates, etc...
// It does not include objects or arrays though
//    one could implement a toString() operator
//    on an object that would uniquely identify
//    the object.
// 
// Uses a javascript object to hold the Set
//
// This is a subset of the Set object designed to be smaller and faster, but
// not as extensible.  This implementation should not be mixed with the Set object
// as in don't pass a miniSet to a Set constructor or vice versa.  Both can exist and be
// used separately in the same project, though if you want the features of the other
// sets, then you should probably just include them and not include miniSet as it's
// really designed for someone who just wants the smallest amount of code to get
// a Set interface.
//
// s.add(key)                      // adds a key to the Set (if it doesn't already exist)
// s.add(key1, key2, key3)         // adds multiple keys
// s.add([key1, key2, key3])       // adds multiple keys
// s.add(otherSet)                 // adds another Set to this Set
// s.add(arrayLikeObject)          // adds anything that a subclass returns true on _isPseudoArray()
// s.remove(key)                   // removes a key from the Set
// s.remove(["a", "b"]);           // removes all keys in the passed in array
// s.remove("a", "b", ["first", "second"]);   // removes all keys specified
// s.has(key)                      // returns true/false if key exists in the Set
// s.isEmpty()                     // returns true/false for whether Set is empty
// s.keys()                        // returns an array of keys in the Set
// s.clear()                       // clears all data from the Set
// s.each(fn)                      // iterate over all items in the Set (return this for method chaining)
//
// All methods return the object for use in chaining except when the point
// of the method is to return a specific value (such as .keys() or .isEmpty())
//-------------------------------------------


// polyfill for Array.isArray
if(!Array.isArray) {
    Array.isArray = function (vArg) {
        return Object.prototype.toString.call(vArg) === "[object Array]";
    };
}

function MiniSet(initialData) {
    // Usage:
    // new MiniSet()
    // new MiniSet(1,2,3,4,5)
    // new MiniSet(["1", "2", "3", "4", "5"])
    // new MiniSet(otherSet)
    // new MiniSet(otherSet1, otherSet2, ...)
    this.data = {};
    this.add.apply(this, arguments);
}

MiniSet.prototype = {
    // usage:
    // add(key)
    // add([key1, key2, key3])
    // add(otherSet)
    // add(key1, [key2, key3, key4], otherSet)
    // add supports the EXACT same arguments as the constructor
    add: function() {
        var key;
        for (var i = 0; i < arguments.length; i++) {
            key = arguments[i];
            if (Array.isArray(key)) {
                for (var j = 0; j < key.length; j++) {
                    this.data[key[j]] = key[j];
                }
            } else if (key instanceof MiniSet) {
                var self = this;
                key.each(function(val, key) {
                    self.data[key] = val;
                });
            } else {
                // just a key, so add it
                this.data[key] = key;
            }
        }
        return this;
    },
    // private: to remove a single item
    // does not have all the argument flexibility that remove does
    _removeItem: function(key) {
        delete this.data[key];
    },
    // usage:
    // remove(key)
    // remove(key1, key2, key3)
    // remove([key1, key2, key3])
    remove: function(key) {
        // can be one or more args
        // each arg can be a string key or an array of string keys
        var item;
        for (var j = 0; j < arguments.length; j++) {
            item = arguments[j];
            if (Array.isArray(item)) {
                // must be an array of keys
                for (var i = 0; i < item.length; i++) {
                    this._removeItem(item[i]);
                }
            } else {
                this._removeItem(item);
            }
        }
        return this;
    },
    // returns true/false on whether the key exists
    has: function(key) {
        return Object.prototype.hasOwnProperty.call(this.data, key);
    },
    // tells you if the Set is empty or not
    isEmpty: function() {
        for (var key in this.data) {
            if (this.has(key)) {
                return false;
            }
        }
        return true;
    },
    // returns an array of all keys in the Set
    // returns the original key (not the string converted form)
    keys: function() {
        var results = [];
        this.each(function(data) {
            results.push(data);
        });
        return results;
    },
    // clears the Set
    clear: function() {
        this.data = {}; 
        return this;
    },
    // iterate over all elements in the Set until callback returns false
    // myCallback(key) is the callback form
    // If the callback returns false, then the iteration is stopped
    // returns the Set to allow method chaining
    each: function(fn) {
        this.eachReturn(fn);
        return this;
    },
    // iterate all elements until callback returns false
    // myCallback(key) is the callback form
    // returns false if iteration was stopped
    // returns true if iteration completed
    eachReturn: function(fn) {
        for (var key in this.data) {
            if (this.has(key)) {
                if (fn.call(this, this.data[key], key) === false) {
                    return false;
                }
            }
        }
        return true;
    }
};

MiniSet.prototype.constructor = MiniSet;

63voto

Tobo Puntos 1248

Puede crear un Objeto con propiedades como

var set = Object.create(null)

que puede actuar como un conjunto y elimina la necesidad de utilizar hasOwnProperty.


var set = Object.create(null); // create an object with no properties

if (A in set) { // 1. is A in the list
  // some code
}
delete set[a]; // 2. delete A from the list if it exists in the list 
set[A] = true; // 3. add A to the list if it is not already present

19voto

hymloth Puntos 2832

Como de ECMAScript 6, el Conjunto de la estructura de datos está integrada una característica. Se ha implementado para que firefox y también funciona para Chrome, después de la habilitación experimental javascript.

8voto

mcrisc Puntos 424

He empezado una implementación de Conjuntos que actualmente funciona bastante bien con los números y cadenas de caracteres. Mi objetivo principal era la diferencia de la operación, así que traté de hacerlo lo más eficiente posible. Horquillas de código y comentarios son bienvenidos!

https://github.com/mcrisc/SetJS

4voto

Dave Newton Puntos 93112

Sí, es una manera sensible-que es todo un objeto es (bueno, para este caso de uso) - un manojo de llaves y/o valores con acceso directo.

Tendría que ver si es que ya existe antes de la adición, o si sólo necesitas indicar la presencia "añadir" lo nuevo en realidad no cambia nada, sólo se establece en el objeto de nuevo.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X