Generalize the CellSet type into a general-purpose Set

This commit is contained in:
Tissevert 2022-08-20 16:23:50 +02:00
parent ac7cd6333b
commit 71c405e5cd
1 changed files with 69 additions and 0 deletions

69
js/Set.js Normal file
View File

@ -0,0 +1,69 @@
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;
}