Incorporando a ideia de Christoph e assumindo alguns métodos de iteração não padrão em arrays e objetos / hashes ( each
e amigos), podemos obter a diferença, união e interseção no tempo linear em cerca de 20 linhas no 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);
}
};
Isso pressupõe que each
e filter
são definidos para matrizes e que temos dois métodos utilitários:
myUtils.keys(hash)
: retorna uma matriz com as chaves do hash
myUtils.select(hash, fnSelector,
fnEvaluator)
: retorna uma matriz com os resultados da chamada fnEvaluator
dos pares chave / valor para os quais
fnSelector
retorna verdadeiro.
O select()
é vagamente inspirado no Common Lisp e é meramente filter()
e map()
agrupado em um. (Seria melhor tê-los definidos emObject.prototype
, mas fazer isso estraga o caos com o jQuery, então me conformei com métodos utilitários estáticos.)
Desempenho: Testando com
var a = [], b = [];
for (var i = 100000; i--; ) {
if (i % 2 !== 0) a.push(i);
if (i % 3 !== 0) b.push(i);
}
dá dois conjuntos com 50.000 e 66.666 elementos. Com esses valores, AB leva cerca de 75ms, enquanto a união e a interseção têm cerca de 150ms cada. (Mac Safari 4.0, usando data Javascript para cronometragem.)
Acho que é uma recompensa decente para 20 linhas de código.