Tutte le soluzioni di cui sopra "funzionano", ma sono meno che ottimali per le prestazioni e affrontano il problema nello stesso modo che cerca in modo lineare tutte le voci in ciascun punto utilizzando Array.prototype.indexOf o Array.prototype.includes . Una soluzione molto più veloce (molto più veloce anche di una ricerca binaria per la maggior parte dei casi) sarebbe quella di ordinare gli array e saltare avanti come si procede come visto di seguito. Tuttavia, un aspetto negativo è che ciò richiede che tutte le voci dell'array siano numeri o stringhe. Inoltre, in alcuni rari casi la ricerca binaria può essere più veloce della ricerca lineare progressiva. Questi casi derivano dal fatto che la mia ricerca lineare progressiva ha una complessità di O (2n 1 + n 2 ) (solo O (n 1 + n 2 ) nella versione C / C ++ più veloce) (dove n 1 è l'array cercato e n 2 è l'array filtro), mentre la ricerca binaria ha una complessità di O (n 1 ceil (log 2 n 2 )) ( ceil = arrotondamento per eccesso - al soffitto ) e, infine, l'indiceOf di ricerca presenta una complessità altamente variabile tra O (n 1 ) e O (n 1 2 )n , con una media di O (n 1 ceil (n 2) ÷ 2)) . Pertanto, indexOf sarà solo il più veloce, in media, nei casi di{1,2} , {1,3} o {x, 1 | x∈N} . Tuttavia, questa non è ancora una rappresentazione perfetta dell'hardware moderno. IndexOf è ottimizzato nativamente nella massima misura possibile nella maggior parte dei browser moderni, il che lo rende molto soggetto alle leggi della predizione delle filiali . Pertanto, se facciamo lo stesso presupposto su indexOf di quanto facciamo con la ricerca progressiva lineare e binaria - che l'array è preordinato - quindi, secondo le statistiche elencate nel link, possiamo aspettarci circa una velocità 6x per IndexOf, spostando la sua complessità tra O (n 1(n 1 , n 2 ) uguale a ÷ 6) e O (n 1 n 2 ), con una media di 7 ÷ 12))O (n 1 ceil (n 2. Infine, si noti che la soluzione seguente non funzionerà mai con gli oggetti perché gli oggetti in JavaScript non possono essere confrontati dai puntatori in JavaScript.
function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
var out=[], value=0;
for (var i=0, len=array.length|0; i < len; i=i+1|0)
if (handle(value = array[i]))
out.push( value );
return out;
}
const Math_clz32 = Math.clz32 || (function(log, LN2){
return function(x) {
return 31 - log(x >>> 0) / LN2 | 0; // the "| 0" acts like math.floor
};
})(Math.log, Math.LN2);
/* USAGE:
filterArrayByAnotherArray(
[1,3,5],
[2,3,4]
) yields [1, 5], and it can work with strings too
*/
function filterArrayByAnotherArray(searchArray, filterArray) {
if (
// NOTE: This does not check the whole array. But, if you know
// that there are only strings or numbers (not a mix of
// both) in the array, then this is a safe assumption.
// Always use `==` with `typeof` because browsers can optimize
// the `==` into `===` (ONLY IN THIS CIRCUMSTANCE)
typeof searchArray[0] == "number" &&
typeof filterArray[0] == "number" &&
(searchArray[0]|0) === searchArray[0] &&
(filterArray[0]|0) === filterArray[0]
) {filterArray
// if all entries in both arrays are integers
searchArray.sort(sortIntArray);
filterArray.sort(sortIntArray);
} else {
searchArray.sort(sortAnyArray);
filterArray.sort(sortAnyArray);
}
var searchArrayLen = searchArray.length, filterArrayLen = filterArray.length;
var progressiveLinearComplexity = ((searchArrayLen<<1) + filterArrayLen)>>>0
var binarySearchComplexity= (searchArrayLen * (32-Math_clz32(filterArrayLen-1)))>>>0;
// After computing the complexity, we can predict which algorithm will be the fastest
var i = 0;
if (progressiveLinearComplexity < binarySearchComplexity) {
// Progressive Linear Search
return fastFilter(searchArray, function(currentValue){
while (filterArray[i] < currentValue) i=i+1|0;
// +undefined = NaN, which is always false for <, avoiding an infinite loop
return filterArray[i] !== currentValue;
});
} else {
// Binary Search
return fastFilter(
searchArray,
fastestBinarySearch(filterArray)
);
}
}
// see https://stackoverflow.com/a/44981570/5601591 for implementation
// details about this binary search algorithm
function fastestBinarySearch(array){
var initLen = (array.length|0) - 1 |0;
const compGoto = Math_clz32(initLen) & 31;
return function(sValue) {
var len = initLen |0;
switch (compGoto) {
case 0:
if (len & 0x80000000) {
const nCB = len & 0x80000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 1:
if (len & 0x40000000) {
const nCB = len & 0xc0000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 2:
if (len & 0x20000000) {
const nCB = len & 0xe0000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 3:
if (len & 0x10000000) {
const nCB = len & 0xf0000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 4:
if (len & 0x8000000) {
const nCB = len & 0xf8000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 5:
if (len & 0x4000000) {
const nCB = len & 0xfc000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 6:
if (len & 0x2000000) {
const nCB = len & 0xfe000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 7:
if (len & 0x1000000) {
const nCB = len & 0xff000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 8:
if (len & 0x800000) {
const nCB = len & 0xff800000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 9:
if (len & 0x400000) {
const nCB = len & 0xffc00000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 10:
if (len & 0x200000) {
const nCB = len & 0xffe00000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 11:
if (len & 0x100000) {
const nCB = len & 0xfff00000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 12:
if (len & 0x80000) {
const nCB = len & 0xfff80000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 13:
if (len & 0x40000) {
const nCB = len & 0xfffc0000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 14:
if (len & 0x20000) {
const nCB = len & 0xfffe0000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 15:
if (len & 0x10000) {
const nCB = len & 0xffff0000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 16:
if (len & 0x8000) {
const nCB = len & 0xffff8000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 17:
if (len & 0x4000) {
const nCB = len & 0xffffc000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 18:
if (len & 0x2000) {
const nCB = len & 0xffffe000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 19:
if (len & 0x1000) {
const nCB = len & 0xfffff000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 20:
if (len & 0x800) {
const nCB = len & 0xfffff800;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 21:
if (len & 0x400) {
const nCB = len & 0xfffffc00;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 22:
if (len & 0x200) {
const nCB = len & 0xfffffe00;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 23:
if (len & 0x100) {
const nCB = len & 0xffffff00;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 24:
if (len & 0x80) {
const nCB = len & 0xffffff80;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 25:
if (len & 0x40) {
const nCB = len & 0xffffffc0;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 26:
if (len & 0x20) {
const nCB = len & 0xffffffe0;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 27:
if (len & 0x10) {
const nCB = len & 0xfffffff0;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 28:
if (len & 0x8) {
const nCB = len & 0xfffffff8;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 29:
if (len & 0x4) {
const nCB = len & 0xfffffffc;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 30:
if (len & 0x2) {
const nCB = len & 0xfffffffe;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 31:
if (len & 0x1) {
const nCB = len & 0xffffffff;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
}
// MODIFICATION: Instead of returning the index, this binary search
// instead returns whether something was found or not.
if (array[len|0] !== sValue) {
return true; // preserve the value at this index
} else {
return false; // eliminate the value at this index
}
};
}
Si prega di consultare il mio altro post qui per maggiori dettagli sull'algoritmo di ricerca binaria utilizzato
Se sei schizzinoso riguardo alle dimensioni del file (che rispetto), puoi sacrificare un po 'di prestazioni al fine di ridurre notevolmente le dimensioni del file e aumentare la manutenibilità.
function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
var out=[], value=0;
for (var i=0, len=array.length|0; i < len; i=i+1|0)
if (handle(value = array[i]))
out.push( value );
return out;
}
/* USAGE:
filterArrayByAnotherArray(
[1,3,5],
[2,3,4]
) yields [1, 5], and it can work with strings too
*/
function filterArrayByAnotherArray(searchArray, filterArray) {
if (
// NOTE: This does not check the whole array. But, if you know
// that there are only strings or numbers (not a mix of
// both) in the array, then this is a safe assumption.
typeof searchArray[0] == "number" &&
typeof filterArray[0] == "number" &&
(searchArray[0]|0) === searchArray[0] &&
(filterArray[0]|0) === filterArray[0]
) {
// if all entries in both arrays are integers
searchArray.sort(sortIntArray);
filterArray.sort(sortIntArray);
} else {
searchArray.sort(sortAnyArray);
filterArray.sort(sortAnyArray);
}
// Progressive Linear Search
var i = 0;
return fastFilter(searchArray, function(currentValue){
while (filterArray[i] < currentValue) i=i+1|0;
// +undefined = NaN, which is always false for <, avoiding an infinite loop
return filterArray[i] !== currentValue;
});
}
Per dimostrare la differenza di velocità, esaminiamo alcuni JSPerf. Per filtrare un array di 16 elementi , la ricerca binaria è circa il 17% più veloce di indexOf mentre filterArrayByAnotherArray è circa il 93% più veloce di indexOf. Per filtrare un array di 256 elementi , la ricerca binaria è circa il 291% più veloce di indexOf mentre filterArrayByAnotherArray è circa il 353% più veloce di indexOf. Per filtrare un array di 4096 elementi , la ricerca binaria è più veloce del 2655% circa rispetto a indexOf mentre filterArrayByAnotherArray è più veloce del 4627% circa rispetto a indexOf.
Filtro inverso (come un gate AND)
La sezione precedente forniva il codice per prendere l'array A e l'array B e rimuovere tutti gli elementi da A che esistono in B:
filterArrayByAnotherArray(
[1,3,5],
[2,3,4]
);
// yields [1, 5]
La prossima sezione fornirà il codice per il filtro inverso, in cui rimuoviamo tutti gli elementi da A che NON esistono in B. Questo processo è funzionalmente equivalente a conservare solo gli elementi comuni ad A e B, come una porta AND:
reverseFilterArrayByAnotherArray(
[1,3,5],
[2,3,4]
);
// yields [3]
Ecco il codice per il filtro inverso:
function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
var out=[], value=0;
for (var i=0, len=array.length|0; i < len; i=i+1|0)
if (handle(value = array[i]))
out.push( value );
return out;
}
const Math_clz32 = Math.clz32 || (function(log, LN2){
return function(x) {
return 31 - log(x >>> 0) / LN2 | 0; // the "| 0" acts like math.floor
};
})(Math.log, Math.LN2);
/* USAGE:
reverseFilterArrayByAnotherArray(
[1,3,5],
[2,3,4]
) yields [3], and it can work with strings too
*/
function reverseFilterArrayByAnotherArray(searchArray, filterArray) {
if (
// NOTE: This does not check the whole array. But, if you know
// that there are only strings or numbers (not a mix of
// both) in the array, then this is a safe assumption.
// Always use `==` with `typeof` because browsers can optimize
// the `==` into `===` (ONLY IN THIS CIRCUMSTANCE)
typeof searchArray[0] == "number" &&
typeof filterArray[0] == "number" &&
(searchArray[0]|0) === searchArray[0] &&
(filterArray[0]|0) === filterArray[0]
) {filterArray
// if all entries in both arrays are integers
searchArray.sort(sortIntArray);
filterArray.sort(sortIntArray);
} else {
searchArray.sort(sortAnyArray);
filterArray.sort(sortAnyArray);
}
var searchArrayLen = searchArray.length, filterArrayLen = filterArray.length;
var progressiveLinearComplexity = ((searchArrayLen<<1) + filterArrayLen)>>>0
var binarySearchComplexity= (searchArrayLen * (32-Math_clz32(filterArrayLen-1)))>>>0;
// After computing the complexity, we can predict which algorithm will be the fastest
var i = 0;
if (progressiveLinearComplexity < binarySearchComplexity) {
// Progressive Linear Search
return fastFilter(searchArray, function(currentValue){
while (filterArray[i] < currentValue) i=i+1|0;
// +undefined = NaN, which is always false for <, avoiding an infinite loop
// For reverse filterning, I changed !== to ===
return filterArray[i] === currentValue;
});
} else {
// Binary Search
return fastFilter(
searchArray,
inverseFastestBinarySearch(filterArray)
);
}
}
// see https://stackoverflow.com/a/44981570/5601591 for implementation
// details about this binary search algorithim
function inverseFastestBinarySearch(array){
var initLen = (array.length|0) - 1 |0;
const compGoto = Math_clz32(initLen) & 31;
return function(sValue) {
var len = initLen |0;
switch (compGoto) {
case 0:
if (len & 0x80000000) {
const nCB = len & 0x80000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 1:
if (len & 0x40000000) {
const nCB = len & 0xc0000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 2:
if (len & 0x20000000) {
const nCB = len & 0xe0000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 3:
if (len & 0x10000000) {
const nCB = len & 0xf0000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 4:
if (len & 0x8000000) {
const nCB = len & 0xf8000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 5:
if (len & 0x4000000) {
const nCB = len & 0xfc000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 6:
if (len & 0x2000000) {
const nCB = len & 0xfe000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 7:
if (len & 0x1000000) {
const nCB = len & 0xff000000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 8:
if (len & 0x800000) {
const nCB = len & 0xff800000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 9:
if (len & 0x400000) {
const nCB = len & 0xffc00000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 10:
if (len & 0x200000) {
const nCB = len & 0xffe00000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 11:
if (len & 0x100000) {
const nCB = len & 0xfff00000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 12:
if (len & 0x80000) {
const nCB = len & 0xfff80000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 13:
if (len & 0x40000) {
const nCB = len & 0xfffc0000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 14:
if (len & 0x20000) {
const nCB = len & 0xfffe0000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 15:
if (len & 0x10000) {
const nCB = len & 0xffff0000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 16:
if (len & 0x8000) {
const nCB = len & 0xffff8000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 17:
if (len & 0x4000) {
const nCB = len & 0xffffc000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 18:
if (len & 0x2000) {
const nCB = len & 0xffffe000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 19:
if (len & 0x1000) {
const nCB = len & 0xfffff000;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 20:
if (len & 0x800) {
const nCB = len & 0xfffff800;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 21:
if (len & 0x400) {
const nCB = len & 0xfffffc00;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 22:
if (len & 0x200) {
const nCB = len & 0xfffffe00;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 23:
if (len & 0x100) {
const nCB = len & 0xffffff00;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 24:
if (len & 0x80) {
const nCB = len & 0xffffff80;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 25:
if (len & 0x40) {
const nCB = len & 0xffffffc0;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 26:
if (len & 0x20) {
const nCB = len & 0xffffffe0;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 27:
if (len & 0x10) {
const nCB = len & 0xfffffff0;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 28:
if (len & 0x8) {
const nCB = len & 0xfffffff8;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 29:
if (len & 0x4) {
const nCB = len & 0xfffffffc;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 30:
if (len & 0x2) {
const nCB = len & 0xfffffffe;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
case 31:
if (len & 0x1) {
const nCB = len & 0xffffffff;
len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
}
}
// MODIFICATION: Instead of returning the index, this binary search
// instead returns whether something was found or not.
// For reverse filterning, I swapped true with false and vice-versa
if (array[len|0] !== sValue) {
return false; // preserve the value at this index
} else {
return true; // eliminate the value at this index
}
};
}
Per la versione più lenta più piccola del codice di filtro inverso, vedere di seguito.
function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
var out=[], value=0;
for (var i=0, len=array.length|0; i < len; i=i+1|0)
if (handle(value = array[i]))
out.push( value );
return out;
}
/* USAGE:
reverseFilterArrayByAnotherArray(
[1,3,5],
[2,3,4]
) yields [3], and it can work with strings too
*/
function reverseFilterArrayByAnotherArray(searchArray, filterArray) {
if (
// NOTE: This does not check the whole array. But, if you know
// that there are only strings or numbers (not a mix of
// both) in the array, then this is a safe assumption.
typeof searchArray[0] == "number" &&
typeof filterArray[0] == "number" &&
(searchArray[0]|0) === searchArray[0] &&
(filterArray[0]|0) === filterArray[0]
) {
// if all entries in both arrays are integers
searchArray.sort(sortIntArray);
filterArray.sort(sortIntArray);
} else {
searchArray.sort(sortAnyArray);
filterArray.sort(sortAnyArray);
}
// Progressive Linear Search
var i = 0;
return fastFilter(searchArray, function(currentValue){
while (filterArray[i] < currentValue) i=i+1|0;
// +undefined = NaN, which is always false for <, avoiding an infinite loop
// For reverse filter, I changed !== to ===
return filterArray[i] === currentValue;
});
}
return arrTwo.indexOf(e) === -1;
codice:var filteredArr = firstArr.filter(el => secondArr.indexOf(el) === -1);