JS.Set

The JS.Set class can be used to model collections of unique objects. A set makes sure that there are no duplicates among its members, and it allows you to use custom equality methods for comparison as well as JavaScript’s === operator.

As well as JS.Set, an additional class called JS.SortedSet is provided. This class keeps all its members in sort order as long as they are mutually comparable, either using JavaScript’s <, <=, ==, >, >= operators or using the Comparable module. Sorting the elements allows this class to guarantee iteration order, and gives the class a performance benefit over the regular JS.Set class, especially on larger data sets. SortedSet is a subclass of Set; its API is identical, only its storage mechanism is different.

If you try to add an object that has an equals() method to a set, that method will be used to compare the object to the set’s members. equals() should accept one argument and return a boolean to indicate whether the two objects are to be considered equal. If no equals() method exists on the object, the === operator is used instead. An example class might look like:

        Widget = new JS.Class({
          initialize: function(name) {
            this.name = name;
          },
          equals: function(object) {
            return (object instanceof this.klass)
                && object.name == this.name;
          }
        });

Bear in mind that uniqueness (and sort order for SortedSet) is only maintained when new objects are added to the set. Objects can be changed such that two objects that are unequal can be made to be equal; if those two objects are members of a set the set is then corrupted. To get around this, all sets have a rebuild() method that throws out any duplicates and fixes sort order.

Creating a set is simple: simply pass an array (or some other enumerable object) with the data to put in the set:

        var evensUnderTen = new JS.Set([2,4,6,8]);

Set and SortedSet include the Enumerable module as long as you load said module before the Set file. The iteration order for Set is arbitrary and is not guaranteed, whereas for SortedSet iteration takes place in sort order. The rest of the API is as follows. As a general rule, any method that returns a new set will return a set of the same type as the receiver, i.e. if set is a Set then set.union(other) returns a new Set, if set is a SortedSet the same call returns a SortedSet.

add(item)

Adds a new item to the set as long as the set does not already contain the item. If item has an equals() method, item.equals() is used for comparison to other set members (see above). Returns a boolean to indicate whether or not the item was added.

        var evensUnderTen = new JS.Set([2,4,6,8]);
        evensUnderTen.add(6)    // -> false
        evensUnderTen.add(0)    // -> true

classify(block, context)

Splits the set into several sets based on the return value of block for each member.

        // Classify by remainder when divided by 3
        
        var s = new JS.Set([1,2,3,4,5,6,7,8,9]);
        var c = s.classify(function(x) {
          return x % 3;
        });
        
        // c[0] == Set{3,6,9}
        // c[1] == Set{1,4,7}
        // c[2] == Set{2,5,8}

clear()

Removes all members from the set.

complement(other)

Returns a new set containing all the members of other that are not in the receiver.

contains(item)

Returns true iff the set contains item.

difference(other)

Returns a new set containing all the members of the receiver that are not in the set other.

        var a = new JS.Set([1,2,3,4,5,6,7,8,9]);
        var b = new JS.Set([2,4,6,8]);
        
        a.difference(b)
        // -> Set{1,3,5,7,9}

divide(block, context)

Similar to classify(block, context) except that the result is given as a set of sets, rather than as key/value pairs.

        // Classify by remainder when divided by 3
        
        var s = new JS.Set([1,2,3,4,5,6,7,8,9]);
        var c = s.divide(function(x) {
          return x % 3;
        });
        
        // c == Set { Set{3,6,9}, Set{1,4,7}, Set{2,5,8} }

equals(set)

Returns true iff set is a Set or a SortedSet with the same members as the receiver.

flatten()

Flattens the set in place, such that any sets nested within the receiver are merged and their members become the receiver’s members.

        var s = new JS.Set([ new JS.Set([3,9,4]),
            new JS.Set([1,7,3,5]), 3, 7 ]);
        
        // s == Set{ Set{3,9,4}, Set{1,7,3,5}, 3, 7}
        
        s.flatten();
        
        // s == Set{3,9,4,1,7,5}

intersection(set)

Returns a new set containing members common to both set and the receiver.

isEmpty()

Returns true iff the receiver has no members.

isProperSubset(other)

Returns true iff the receiver is a proper subset of the set other, that is if all the members of the receiver are also in other, and the receiver is a smaller set than other.

isProperSuperset(other)

Returns true iff the receiver is a proper superset of the set other, that is if all the members of other are also in the receiver, and the receiver is a larger set than other.

isSubset(other)

Returns true iff the receiver is a subset of the set other, that is if all the members of the receiver are also members of other.

isSuperset(other)

Returns true iff the receiver is a superset of the set other, that is if all the members of other are also members of the receiver.

merge(set)

Adds all the members of set to the receiver.

product(set)

Returns a new (always non-sorted) set of all possible ordered pairs whose first member is in the receiver and whose second member is in set.

        var a = new JS.Set([1,2]), b = new JS.Set([3,4]);
        var prod = a.product(b);
        
        // prod == Set{ [1,3], [1,4], [2,3], [2,4] }

rebuild()

Acts as an integrity check on the receiver. If some of the objects in the set have changed such that they are now equal then any duplicates are discarded. For SortedSet instances, this also sorts the set if any objects have changed such that they are now in the wrong position.

remove(item)

Removes the member item (i.e. whichever member is equal to item) from the receiver.

removeIf(predicate, context)

Removes all the members of the set for which predicate returns true.

        var s = new JS.Set([1,2,3,4,5,6,7,8,9]);
        
        // Remove multiples of 3
        s.removeIf(function(x) { return x % 3 == 0 });
        
        // s == Set{1,2,4,5,7,8}

replace(other)

Removes all the members from the receiver and replaces them with those of the set other.

subtract(list)

Removes all the members of list from the receiver. This is similar to difference, except that it modifies the receiving set in place rather than returning a new set.

union(set)

Returns a new set containing all the members from set and the receiver.

xor(other)

Returns a new set containing members that are either in other or in the receiver, but not in both. This is equivalent to:

        // a.xor(b) ->
        (a.union(b)).difference(a.intersection(b))