Wenn eachwir die Idee von Christoph einbeziehen und einige nicht standardmäßige Iterationsmethoden für Arrays und Objekte / Hashes ( und Freunde) annehmen , können wir Differenz, Vereinigung und Schnittmenge in linearer Zeit in insgesamt etwa 20 Zeilen festlegen:
var setOPs = {
minusAB : function (a, b) {
var h = {};
b.each(function (v) { h[v] = true; });
return a.filter(function (v) { return !h.hasOwnProperty(v); });
},
unionAB : function (a, b) {
var h = {}, f = function (v) { h[v] = true; };
a.each(f);
b.each(f);
return myUtils.keys(h);
},
intersectAB : function (a, b) {
var h = {};
a.each(function (v) { h[v] = 1; });
b.each(function (v) { h[v] = (h[v] || 0) + 1; });
var fnSel = function (v, count) { return count > 1; };
var fnVal = function (v, c) { return v; };
return myUtils.select(h, fnSel, fnVal);
}
};
Dies setzt voraus, dass eachund filterfür Arrays definiert sind und dass wir zwei Dienstprogrammmethoden haben:
myUtils.keys(hash): Gibt ein Array mit den Schlüsseln des Hash zurück
myUtils.select(hash, fnSelector,
fnEvaluator): Gibt ein Array mit den Ergebnissen des Aufrufs fnEvaluator
der Schlüssel / Wert-Paare zurück, für die
fnSelectortrue zurückgegeben wird.
Das select()ist lose von Common Lisp inspiriert und ist nur filter()und map()in einem gerollt. (Es wäre besser, sie definiert zu habenObject.prototype , aber dies führt zu einem Chaos mit jQuery, sodass ich mich für statische Dienstprogrammmethoden entschieden habe.)
Leistung: Testen mit
var a = [], b = [];
for (var i = 100000; i--; ) {
if (i % 2 !== 0) a.push(i);
if (i % 3 !== 0) b.push(i);
}
gibt zwei Sätze mit 50.000 und 66.666 Elementen. Mit diesen Werten dauert AB ungefähr 75 ms, während Vereinigung und Schnittpunkt jeweils ungefähr 150 ms betragen. (Mac Safari 4.0 mit Javascript-Datum für das Timing.)
Ich denke, das ist eine anständige Auszahlung für 20 Codezeilen.