Permalink
Browse files

Added ObjectSet

  • Loading branch information...
refset committed Mar 25, 2013
1 parent 5410bbb commit ffd898b1898d7f9c4f3e967f7ac137f6689142b0
Showing with 693 additions and 2 deletions.
  1. +9 −1 README.md
  2. +174 −1 lib/simplesets.js
  3. +510 −0 lib/simplesets.js~
View
@@ -99,13 +99,21 @@ The condition for determining whether two values are equal is the `===` operator
Specialized sets
----------
+`StringSet`:
+
If all of your set members have unique string representations, then you can create a set using object properties to keep track of the members. This takes advantage of the fast built-in object type in JavaScript, and is generally better than using general-purpose sets if there will not be collisions, e.g. a set containing both the number 42 and the string "42".
The `StringSet` class behaves just like the `Set` class, but it uses this object-based encoding and requires that all set members have unique string representations. Instantiate it with `new StringSet(items)`, and the API is the same as described above.
Note that `Set` will generally be faster and more memory-efficient than `StringSet` for sets with fewer than around 110 elements. `StringSet` is good for large sets, though.
+`ObjectSet`:
+
+The same API and behaviour as 'StringSet' except keys are derived from the string property at `object.id`.
+
+For example... `new ObjectSet([{id:"one", someValue:42},{id:"two", someValue:43}])`
+
License
-------
-This is released under an [MIT License](http://en.wikipedia.org/wiki/MIT_License), like node.js itself.
+This is released under an [MIT License](http://en.wikipedia.org/wiki/MIT_License), like node.js itself.
View
@@ -330,4 +330,177 @@ exports.StringSet = function(items) {
this.add(items[i]);
};
-exports.StringSet.prototype = StringSetPrototype;
+exports.StringSet.prototype = StringSetPrototype;
+
+
+var ObjectSetPrototype = {
+ // Does this set contain an element x with id x.id? Returns true or false.
+ has: function(x) {
+ return this._items.hasOwnProperty(x.id);
+ },
+
+ // Add an element x to this set, and return this set.
+ add: function(x) {
+ if (!this.has(x)) {
+ this._items[x.id] = x;
+ this._size++;
+ }
+ return this;
+ },
+
+ // Remove an element x from this set, if it is part of the set. If
+ // it is not part of the set, do nothing. Returns this set.
+ remove: function(x) {
+ if (this.has(x)) {
+ delete this._items[x.id];
+ this._size--;
+ }
+ return this;
+ },
+
+ // Return a new set containing the items found in either this set,
+ // the other set, or both.
+ union: function(other) {
+ var result = new exports.ObjectSet();
+ for (var x in this._items) result.add(this._items[x.id]);
+ for (x in other._items) result.add(other._items[x.id]);
+ return result;
+ },
+
+ // Return a new set containing the items found in both this set
+ // and the other set.
+ intersection: function(other) {
+ var result = new exports.ObjectSet();
+ for (var x in other._items)
+ if (this._items.hasOwnProperty(x.id))
+ result.add(this._items[x.id]);
+ return result;
+ },
+
+ // Return a new set containing the items in this set that are not
+ // in the other set.
+ difference: function(other) {
+ var result = new exports.ObjectSet();
+ for (var x in this._items)
+ if (!other._items.hasOwnProperty(x.id))
+ result.add(this._items[x]);
+ return result;
+ },
+
+ // Return a new set containing the items in either this set or the
+ // other set, but not both.
+ symmetric_difference: function(other) {
+ // Hideously inefficient -- but who uses this function, anyway?
+ return this.union(other).difference(this.intersection(other));
+ },
+
+ // Return true if every element of this set is in the other set.
+ issubset: function(other) {
+ for (var x in this._items)
+ if (!other._items.hasOwnProperty(x.id))
+ return false;
+ return true;
+ },
+
+ // Return true if every element of the other is in this set.
+ issuperset: function(other) {
+ return other.issubset(this);
+ },
+
+ // Return a copy of the items in the set, as an array.
+ array: function() {
+ var arr = [];
+ for (var x in this._items)
+ arr.push(this._items[x]);
+ return arr;
+ },
+
+ // Return the size of the set.
+ size: function() {
+ return this._size;
+ },
+
+ // Return a shallow copy of the set.
+ copy: function() {
+ var result = new exports.ObjectSet();
+ for (var x in this._items) result.add(this._items[x]);
+ return result;
+ },
+
+ // Return a random element of the set, or null if the set is
+ // empty. Unlike pop, does not remove the element from the set.
+ pick: function() {
+ if (this._size === 0) return null;
+
+ var i = Math.floor(Math.random() * this._size);
+ for (var x in this._items) {
+ if (i === 0) return this._items[x];
+ i--;
+ }
+ // This should never happen
+ return null;
+ },
+
+ // Remove and return a random element of the set, or null if the
+ // set is empty.
+ pop: function() {
+ if (this._size === 0) return null;
+
+ var i = Math.floor(Math.random() * this._size);
+ for (var x in this._items) {
+ if (i === 0) {
+ var ret = this._items[x];
+ this.remove(this._items[x]);
+ return ret;
+ }
+ i--;
+ }
+ // This should never happen
+ return null;
+ },
+
+ // Return true if this set equals another set, i.e. if every
+ // element in each set is equal to an element in the other set.
+ equals: function(other) {
+ // Common case: sets are different size.
+ if (this.size() !== other.size()) return false;
+
+ // If sets are the same size, we can just check to see that
+ // every element in this set corresponds to an element in the
+ // other set.
+ for (var x in this._items)
+ if (!other.has(this._items[x]))
+ return false;
+ return true;
+ },
+
+ // Call a callback function on each element of the set. If the set
+ // is changed by the callback, the results are undefined.
+ // Callback takes the same parameters as the forEach method of
+ // arrays: value, index, set
+ // Takes an optional parameter that sets what this is bound to.
+ each: function(callback, thisArg) {
+ // If there's no callback, don't bother.
+ if (!callback) return;
+
+ if (thisArg) callback = callback.bind(thisArg);
+
+ for (var x in this._items)
+ callback(this._items[x], x, this);
+ }
+}
+
+// A special type of set, where all keys have object.id representations where values are object {}
+exports.ObjectSet = function(items) {
+ // All items are stored in an object.
+ this._items = {};
+ // We maintain a size variable for the cardinality of the set.
+ this._size = 0;
+
+ // If initial items were given, add them to the set.
+ if (typeof items !== "undefined")
+ for (var i = 0; i < items.length; i++)
+ this.add(items[i]);
+};
+
+exports.ObjectSet.prototype = ObjectSetPrototype;
Oops, something went wrong.

0 comments on commit ffd898b

Please sign in to comment.