return { make: make }; function make(type) { if(type == undefined) { var id = function(x) {return x;}; type = {toKey: id, ofKey: id}; } function Set(s) { this.elements = {}; if(Array.isArray(s)) { s.forEach(this.add.bind(this)); } else if(s != undefined) { this.add(s); } } Set.prototype.add = function(e) { this.elements[type.toKey(e)] = true; }; Set.prototype.remove = function(e) { delete this.elements[type.toKey(e)]; }; Set.prototype.contains = function(e) { return !!this.elements[type.toKey(e)]; }; Set.prototype.size = function() { return Object.keys(this.elements).length; }; Set.prototype.toList = function() { var result = []; for(var k in this.elements) { result.push(type.ofKey(k)); } return Array.from(result).sort(); } Set.prototype.iter = function(f) { this.toList().forEach(f); }; Set.prototype.map = function(f) { return this.toList().map(f); }; Set.prototype.equals = function(set) { var sorted = [this.toList(), set.toList()]; return sorted[0].length == sorted[1].length && sorted[0].every(function(x) {return x == sorted[1].shift();}); } Set.prototype.subset = function(predicate) { var newSet = new Set(); this.iter(function(e) { if(predicate(e)) { newSet.add(e); } }); return newSet; }; Set.prototype.difference = function(set) { return this.subset(function(e) {return !set.contains(e);}); } Set.prototype.intersection = function(set) { return this.subset(function(e) {return set.contains(e);}); } Set.union = function(sets) { var newSet = new Set(); for(var i = 0; i < sets.length; i++) { sets[i].iter(newSet.add.bind(newSet)); } return newSet; } return Set; }