Incorporando l'idea di Christoph e assumendo un paio di metodi di iterazione non standard su array e oggetti / hash ( each
e amici), possiamo ottenere la differenza di set, l'unione e l'intersezione in tempo lineare in circa 20 righe totali:
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);
}
};
Ciò presuppone che each
efilter
siano definiti per gli array e che abbiamo due metodi di utilità:
myUtils.keys(hash)
: restituisce un array con le chiavi dell'hash
myUtils.select(hash, fnSelector,
fnEvaluator)
: restituisce un array con i risultati della chiamata fnEvaluator
sulle coppie chiave / valore per le quali
fnSelector
restituisce true.
Il select()
è vagamente ispirato a Common Lisp, ed è semplicemente filter()
e map()
arrotolato in uno. (Sarebbe meglio averli definiti Object.prototype
, ma così facendo si rovina il caos con jQuery, quindi ho optato per metodi di utilità statici.)
Prestazioni: test con
var a = [], b = [];
for (var i = 100000; i--; ) {
if (i % 2 !== 0) a.push(i);
if (i % 3 !== 0) b.push(i);
}
fornisce due set con 50.000 e 66.666 elementi. Con questi valori AB impiega circa 75 ms, mentre l'unione e l'intersezione sono circa 150 ms ciascuna. (Mac Safari 4.0, utilizzando Javascript Date per i tempi.)
Penso che sia un discreto guadagno per 20 righe di codice.