Jak odfiltrować tablicę ze wszystkich elementów innej tablicy

139


Chciałbym zrozumieć najlepszy sposób filtrowania tablicy ze wszystkich elementów innej . Próbowałem z funkcją filtru, ale nie przychodzi mi do głowy, jak nadać jej wartości, które chcę usunąć.
Coś jak:

var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallback);
// filteredArray should now be [1,3]


function myCallBack(){
    return element ! filteredArray; 
    //which clearly can't work since we don't have the reference <,< 
}

jeśli funkcja filtrująca nie jest użyteczna, jak byś to zaimplementował?
Edycja: sprawdziłem możliwe zduplikowane pytanie i może być przydatne dla tych, którzy łatwo rozumieją JavaScript. Odpowiedź zaznaczona jako dobra ułatwia sprawę.

Koop4
źródło
8
Przekaż drugą tablicę, aby odfiltrować wywołanie zwrotne i użyj return arrTwo.indexOf(e) === -1; kodu: var filteredArr = firstArr.filter(el => secondArr.indexOf(el) === -1);
Tushar
1
Możliwy duplikat tablicy .filter () przy użyciu elementów innej tablicy
Dawid Rutkowski
czy obie tablice są uporządkowane?
Nina Scholz
tablice nie są uporządkowane, również druga tablica ma losową liczbę elementów.
Koop4

Odpowiedzi:

145

Możesz użyć thisparametru filter()funkcji, aby uniknąć przechowywania tablicy filtrów w zmiennej globalnej.

var filtered = [1, 2, 3, 4].filter(
    function(e) {
      return this.indexOf(e) < 0;
    },
    [2, 4]
);
console.log(filtered);

Simon Cześć
źródło
To działa jak urok. Czy można przenieść tę funkcję na zewnątrz i nazwać ją w bardziej zrozumiały sposób? Na przykład: var filter = [1,2,3,4] .filter (myfunct (), [2,4]);
Koop4
1
Jasne: var myFunct = function (e) {return this.indexOf (e) <0;}; var filter = [1, 2, 3, 4] .filter (myFunct, [2,4]);
Simon Hi
1
Czy można to osiągnąć za pomocą wyrażenia lambda w ES2016 lub TypesScript?
Prabu
Kiedy używam tego podejścia, drugi parametr filtru nie trafia do mojej funkcji jako this. thiszawsze wydaje się być nieokreślone ?! Dziwne
coś
149

Zrobiłbym co następuje;

var arr = [1,2,3,4],
    brr = [2,4],
    res = arr.filter(f => !brr.includes(f));
console.log(res);

Redu
źródło
6
Gwiazda rocka. Dziękuję, było to niezwykle pomocne w rozwiązaniu nieco innego problemu. const filteredResults = this.state.cards.filter( result => !this.state.filterOut.includes(result.category) ) Odfiltrowywanie tablicy obiektów na podstawie tablicy wartości w komponencie reagującym: gdzie this.state.cards w tablicy obiektów, a this.state.filterOut jest tablicą wartości odpowiadających kluczowi „category” w obiektach, które Chciałem usunąć.
Josh Pittman
Wiem, to starsza odpowiedź, ale po prostu chciałem powiedzieć, że podobała mi się ta odpowiedź o wiele bardziej i pomogła mi w rozwiązaniu jednego z moich problemów. Jest bardzo czytelny i dzięki temu łatwiej mi było lepiej zrozumieć problem.
ak
1
include będzie działać tylko z ES7. Jeśli używasz ES6, użyj zaakceptowanego rozwiązania.
rudrasiva86
39
var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallBack);

function myCallBack(el){
  return anotherOne.indexOf(el) < 0;
}

W wywołaniu zwrotnym sprawdzasz, czy każda wartość array jest wanotherOne

https://jsfiddle.net/0tsyc1sx/

Jeśli używasz lodash.js, użyj_.difference

filteredArray = _.difference(array, anotherOne);

Próbny

Jeśli masz tablicę obiektów:

var array = [{id :1, name :"test1"},{id :2, name :"test2"},{id :3, name :"test3"},{id :4, name :"test4"}];

var anotherOne = [{id :2, name :"test2"}, {id :4, name :"test4"}];

var filteredArray  = array.filter(function(array_el){
   return anotherOne.filter(function(anotherOne_el){
      return anotherOne_el.id == array_el.id;
   }).length == 0
});

Demo tablica obiektów

Demo tablica różnic obiektów z lodash

AshBringer
źródło
Cześć, czy możesz rozszerzyć ten w tablicy obiektów? Będę bardzo wdzięczny
Roel
Czy używasz lodash?
AshBringer
Nie, proszę pana, wolę postępować zgodnie z metodą oddzwaniania
Roel
cóż, sir, to naprawdę zadziałało, ale oprócz identyfikatora, jak mogę filtrować inną nazwę za pomocą nazwy?
Roel
Hummm ... Po prostu trzeba się do zmian idw anotherOne_el.id == array_el.idz kluczem cokolwiek masz w swoim własnym obiekcie. Powinieneś zdobyć wiedzę na temat tablic i obiektów w javascript, pomoże ci to lepiej zrozumieć odpowiedź
AshBringer
26

        /* Here's an example that uses (some) ES6 Javascript semantics to filter an object array by another object array. */

        // x = full dataset
        // y = filter dataset
        let x = [
            {"val": 1, "text": "a"},
            {"val": 2, "text": "b"},
            {"val": 3, "text": "c"},
            {"val": 4, "text": "d"},
            {"val": 5, "text": "e"}
            ],
            y = [
            {"val": 1, "text": "a"},
            {"val": 4, "text": "d"}               
            ];

        // Use map to get a simple array of "val" values. Ex: [1,4]
        let yFilter = y.map(itemY => { return itemY.val; });

        // Use filter and "not" includes to filter the full dataset by the filter dataset's val.
        let filteredX = x.filter(itemX => !yFilter.includes(itemX.val));

        // Print the result.
        console.log(filteredX);

David Alan Condit
źródło
Dokładnie to, czego potrzebowałem. Dzięki
vikrantnegi
12

Poniższy kod to najprostszy sposób filtrowania tablicy w odniesieniu do innej tablicy. Obie tablice mogą zawierać obiekty zamiast wartości.

let array1 = [1, 3, 47, 1, 6, 7];
let array2 = [3, 6];
let filteredArray1 = array1.filter(el => array2.includes(el));
console.log(filteredArray1); 

Wynik: [3, 6]

Awais Jameel
źródło
8

Jest wiele odpowiedzi na Twoje pytanie, ale nie widzę nikogo używającego wyrażenia lambda:

var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(x => anotherOne.indexOf(x) < 0);
Mati Cassanelli
źródło
6

Wszystkie powyższe rozwiązania "działają", ale są mniej niż optymalne dla wydajności i wszystkie podchodzą do problemu w ten sam sposób, czyli liniowe przeszukiwanie wszystkich wpisów w każdym punkcie przy użyciu Array.prototype.indexOf lub Array.prototype.includes . Znacznie szybszym rozwiązaniem (o wiele szybszym nawet niż wyszukiwanie binarne dla większości przypadków) byłoby posortowanie tablic i przeskoczenie do przodu w trakcie, jak pokazano poniżej. Jednak jedną wadą jest to, że wymaga to, aby wszystkie wpisy w tablicy były liczbami lub łańcuchami. Jednak w niektórych rzadkich przypadkach wyszukiwanie binarne może być szybsze niż progresywne wyszukiwanie liniowe. Przypadki te wynikają z faktu, że moje progresywne wyszukiwanie liniowe ma złożoność O (2n 1 + n 2 ) (tylko O (n 1+ n 2 ) w szybszej wersji C / C ++) (gdzie n 1 to przeszukiwana tablica an 2 to tablica filtrów), podczas gdy wyszukiwanie binarne ma złożoność O (n 1 ceil (log 2 n 2 )) ( ceil = zaokrąglenie w górę - do górnego pułapu ) i wreszcie indeks wyszukiwania ma wysoce zmienną złożoność między O (n 1 ) a O (n 1 n 2 ) , uśredniając do O (n 1 ceil (n 2) ÷ 2)) . Zatem indexOf będzie średnio najszybszy tylko w przypadkach(n 1 , n 2 ) równa {1,2} , {1,3} lub {x, 1 | x∈N} . Jednak nadal nie jest to idealna reprezentacja nowoczesnego sprzętu. IndexOf jest natywnie zoptymalizowany w najszerszym możliwym zakresie, jaki można sobie wyobrazić w większości nowoczesnych przeglądarek, dzięki czemu podlega prawom przewidywania gałęzi . Tak więc, jeśli przyjmiemy to samo założenie na indexOf, co w przypadku progresywnego wyszukiwania liniowego i binarnego - że tablica jest wstępnie posortowana - to zgodnie ze statystykami podanymi w linku możemy spodziewać się około 6-krotnego przyspieszenia dla IndexOf, przesunięcie jego złożoności między O (n 1 ÷ 6) a O (n 1 n 2 ), uśredniając do O (n 1 ceil (n 2 7 ÷ 12)) . Na koniec zwróć uwagę, że poniższe rozwiązanie nigdy nie będzie działać z obiektami, ponieważ obiektów w JavaScript nie można porównywać za pomocą wskaźników w 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
    }
  };
}

Zobacz mój drugi post , aby uzyskać więcej informacji na temat zastosowanego algorytmu wyszukiwania binarnego

Jeśli niepokoisz się rozmiarem pliku (co szanuję), możesz poświęcić trochę wydajności, aby znacznie zmniejszyć rozmiar pliku i zwiększyć łatwość konserwacji.

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;
    });
}

Aby udowodnić różnicę w szybkości, przyjrzyjmy się niektórym plikom JSPerf. W przypadku filtrowania tablicy 16 elementów , wyszukiwanie binarne jest około 17% szybsze niż indexOf, podczas gdy filterArrayByAnotherArray jest około 93% szybsze niż indexOf. W przypadku filtrowania tablicy składającej się z 256 elementów , wyszukiwanie binarne jest około 291% szybsze niż indexOf, podczas gdy filterArrayByAnotherArray jest około 353% szybsze niż indexOf. W przypadku filtrowania tablicy zawierającej 4096 elementów wyszukiwanie binarne jest około 2655% szybsze niż indexOf, podczas gdy filterArrayByAnotherArray jest około 4627% szybsze niż indexOf.

Odwrotne filtrowanie (jak bramka AND)

W poprzedniej sekcji podano kod, który pobierze tablicę A i tablicę B oraz usunie wszystkie elementy z A, które istnieją w B:

filterArrayByAnotherArray(
    [1,3,5],
    [2,3,4]
);
// yields [1, 5]

Ta następna sekcja zawiera kod do odwrotnego filtrowania, w którym usuwamy wszystkie elementy z A, które NIE istnieją w B. Ten proces jest funkcjonalnie równoważny zachowaniu tylko elementów wspólnych dla obu A i B, takich jak bramka AND:

reverseFilterArrayByAnotherArray(
    [1,3,5],
    [2,3,4]
);
// yields [3]

Oto kod odwrotnego filtrowania:

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
    }
  };
}

Dla wolniejszej, mniejszej wersji kodu odwrotnego filtrowania, zobacz poniżej.

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;
    });
}
Jack Giffin
źródło
4
Dziękuję za odpowiedź, jestem pewien, że prędzej czy później komuś się przyda, nawet jeśli powinien być używany w skrajnych przypadkach (tj. Tylko wtedy, gdy pojawiają się problemy z wydajnością). We wszystkich innych przypadkach sugerowałbym użycie wersji możliwej do utrzymania / czytelnej.
Koop4
1
@JackGiffin Myślę, że przez czytelność oznacza łatwy w obsłudze i szybki do przeczytania i zrozumienia przez przeciętnego programistę WWW, gdy potrzebna jest zmiana lub proste zrozumienie. Świetne rozwiązanie, ale nie w większości przypadków.
zardilior
1
@JackGiffin wczesna optymalizacja jest jedną z najgorszych rzeczy w projektach, wydajność powinna być ogólnie stosowana na różne sposoby, pisząc wydajny kod, jeśli jest wystarczająco prosty, co oznacza, że ​​nie należy pisać bezpośrednio przez zły kod i kiedy potrzebna jest optymalizacja, ponieważ wydajność nie spełnia wymagań . Tak więc osoba taka jak ty powinna pracować nad optymalizacją innych projektów, które wymagają umiejętności wywodzących się z obsesji. Mam nadzieję, że to pomoże :)
zardilior
1
@zardilior To naprawdę pomaga. Bardzo dziękuję za radę zardilior. Wezmę to sobie do serca i zacznę działać.
Jack Giffin,
1
@JackGiffin cieszy się, że mogę służyć
zardilior
3

OA można również zaimplementować w ES6 w następujący sposób

ES6:

 const filtered = [1, 2, 3, 4].filter(e => {
    return this.indexOf(e) < 0;
  },[2, 4]);
Hemadri Dasari
źródło
Poza składnią strzałek, jaką przewagę ES6 ma to rozwiązanie, jeśli chodzi o filtrowanie?
Carl Edwards
1

Możesz skonfigurować funkcję filtru, aby iterowała po „tablicy filtrów”.

var arr = [1, 2, 3 ,4 ,5, 6, 7];
var filter = [4, 5, 6];

var filtered = arr.filter(
  function(val) {
    for (var i = 0; i < filter.length; i++) {
      if (val == filter[i]) {
        return false;
      }
    }
    return true;
  }
); 
metapod
źródło
1

Możesz użyć filtru, a następnie dla funkcji filtrującej użyć redukcji tablicy filtrującej, która sprawdza i zwraca prawdę, gdy znajdzie dopasowanie, a następnie odwraca po powrocie (!). Funkcja filtrująca jest wywoływana raz na element tablicy. Nie wykonujesz porównania żadnego z elementów funkcji w swoim poście.

var a1 = [1, 2, 3, 4],
  a2 = [2, 3];

var filtered = a1.filter(function(x) {
  return !a2.reduce(function(y, z) {
    return x == y || x == z || y == true;
  })
});

document.write(filtered);

Goblinlord
źródło
1

var arr1= [1,2,3,4];
var arr2=[2,4]

function fil(value){
return value !=arr2[0] &&  value != arr2[1]
}

document.getElementById("p").innerHTML= arr1.filter(fil)
<!DOCTYPE html> 
<html> 
<head> 
</head>
<body>
<p id="p"></p>

hypemichael
źródło
Dzięki, działa, ale wolałbym zachować lokalny zakres. Również arr2 ma losową liczbę elementów.
Koop4
1

function arr(arr1,arr2){
  
  function filt(value){
    return arr2.indexOf(value) === -1;
    }
  
  return arr1.filter(filt)
  }

document.getElementById("p").innerHTML = arr([1,2,3,4],[2,4])
<p id="p"></p>

hypemichael
źródło
1

Bardziej elastyczna tablica filtrująca z innej tablicy, która zawiera właściwości obiektu

function filterFn(array, diffArray, prop, propDiff) {
    diffArray = !propDiff ? diffArray : diffArray.map(d => d[propDiff])
    this.fn = f => diffArray.indexOf(f) === -1
    if (prop) {
         return array.map(r => r[prop]).filter(this.fn)
    } else {
         return array.filter(this.fn)
    }
}

//You can use it like this;

var arr = [];

for (var i = 0; i < 10; i++) {
    var obj = {}
    obj.index = i
    obj.value = Math.pow(2, i)
    arr.push(obj)
}

var arr2 = [1, 2, 3, 4, 5]

var sec = [{t:2}, {t:99}, {t:256}, {t:4096}]

var log = console.log.bind(console)

var filtered = filterFn(arr, sec, 'value', 't')

var filtered2 = filterFn(arr2, sec, null, 't')

log(filtered, filtered2)

syarul
źródło
1

Możesz napisać ogólną funkcję filterByIndex () i skorzystać z wnioskowania o typie w TS, aby zaoszczędzić sobie kłopotów z funkcją wywołania zwrotnego:

powiedzmy, że masz swoją tablicę [1,2,3,4], którą chcesz przefiltrować () z indeksami określonymi w tablicy [2,4].

var filtered = [1,2,3,4,].filter(byIndex(element => element, [2,4]))

funkcja byIndex oczekuje funkcji elementu i tablicy i wygląda następująco:

byIndex = (getter: (e:number) => number, arr: number[]) => (x: number) => {
    var i = getter(x);
    return arr.indexOf(i); 
}

wynik jest wtedy

filtered = [1,3]
lama
źródło
1

Poniższe przykłady służą new Set()do tworzenia przefiltrowanej tablicy, która ma tylko unikalne elementy:

Tablica z prymitywnymi typami danych: string, number, boolean, null, undefined, symbol:

const a = [1, 2, 3, 4];
const b = [3, 4, 5];
const c = Array.from(new Set(a.concat(b)));

Tablica z obiektami jako elementami:

const a = [{id:1}, {id: 2}, {id: 3}, {id: 4}];
const b = [{id: 3}, {id: 4}, {id: 5}];
const stringifyObject = o => JSON.stringify(o);
const parseString = s => JSON.parse(s);
const c = Array.from(new Set(a.concat(b).map(stringifyObject)), parseString);
didinko
źródło
1

Poniżej przykład

let firstArray=[1,2,3,4,5];
let secondArray=[2,3];  
let filteredArray = firstArray.filter((a) => secondArray.indexOf(a)<0);
console.log(filteredArray); //above line gives [1,4,5]

Sagar M
źródło
0

Rozwiązanie Jacka Giffina jest świetne, ale nie działa dla tablic z liczbami większymi niż 2 ^ 32. Poniżej znajduje się refaktoryzowana, szybka wersja filtrująca tablicę w oparciu o rozwiązanie Jacka, ale działa ona dla tablic 64-bitowych.

const Math_clz32 = Math.clz32 || ((log, LN2) => x => 31 - log(x >>> 0) / LN2 | 0)(Math.log, Math.LN2);

const filterArrayByAnotherArray = (searchArray, filterArray) => {

    searchArray.sort((a,b) => a > b);
    filterArray.sort((a,b) => a > b);

    let searchArrayLen = searchArray.length, filterArrayLen = filterArray.length;
    let progressiveLinearComplexity = ((searchArrayLen<<1) + filterArrayLen)>>>0
    let binarySearchComplexity = (searchArrayLen * (32-Math_clz32(filterArrayLen-1)))>>>0;

    let i = 0;

    if (progressiveLinearComplexity < binarySearchComplexity) {
      return searchArray.filter(currentValue => {
        while (filterArray[i] < currentValue) i=i+1|0;
        return filterArray[i] !== currentValue;
      });
    }
    else return searchArray.filter(e => binarySearch(filterArray, e) === null);
}

const binarySearch = (sortedArray, elToFind) => {
  let lowIndex = 0;
  let highIndex = sortedArray.length - 1;
  while (lowIndex <= highIndex) {
    let midIndex = Math.floor((lowIndex + highIndex) / 2);
    if (sortedArray[midIndex] == elToFind) return midIndex; 
    else if (sortedArray[midIndex] < elToFind) lowIndex = midIndex + 1;
    else highIndex = midIndex - 1;
  } return null;
}
Edgard
źródło