Incorporando la idea de Christoph y asumiendo un par de métodos de iteración no estándar en matrices y objetos / hashes ( each
y amigos), podemos obtener la diferencia de conjuntos, la unión y la intersección en tiempo lineal en aproximadamente 20 líneas en total:
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);
}
};
Esto supone que each
y filter
están definidos para matrices, y que tenemos dos métodos de utilidad:
myUtils.keys(hash)
: devuelve una matriz con las claves del hash
myUtils.select(hash, fnSelector,
fnEvaluator)
: devuelve una matriz con los resultados de llamar fnEvaluator
a los pares clave / valor para los que
fnSelector
devuelve verdadero.
El select()
está vagamente inspirado en Common Lisp, y es simplemente filter()
y map()
en uno. (Sería mejor tenerlos definidos Object.prototype
, pero hacerlo arruina el caos con jQuery, así que me conformé con métodos de utilidad estáticos).
Rendimiento: prueba con
var a = [], b = [];
for (var i = 100000; i--; ) {
if (i % 2 !== 0) a.push(i);
if (i % 3 !== 0) b.push(i);
}
da dos conjuntos con 50.000 y 66.666 elementos. Con estos valores AB tarda unos 75 ms, mientras que la unión y la intersección son de unos 150 ms cada una. (Mac Safari 4.0, usando Javascript Date para la sincronización).
Creo que es una recompensa decente por 20 líneas de código.