330


I'd like to understand the best way to filter an array from all elements of another one. I tried with the filter function, but it doesn't come to me how to give it the values i want to remove.
Something Like:

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

in case the filter function is not usefull, how would you implement this ?
Edit: i checked the possible duplicate question, and it could be useful for those who understand javascript easily. The answer checked as good makes things easy.

Robdll
  • 5,865
  • 7
  • 31
  • 51
  • 13
    Pass the other array to filter callback and use `return arrTwo.indexOf(e) === -1;` **Code:** `var filteredArr = firstArr.filter(el => secondArr.indexOf(el) === -1);` – Tushar Jan 20 '16 at 13:39
  • 1
    Possible duplicate of [.filter() array using another array's elements](http://stackoverflow.com/questions/7353917/filter-array-using-another-arrays-elements) – Dawid Rutkowski Jan 20 '16 at 13:40
  • are both arrays ordered? – Nina Scholz Jan 20 '16 at 13:52
  • array are not ordered, also, the second array has a random number of elements. – Robdll Jan 20 '16 at 15:42

24 Answers24

491

I would do as follows;

var arr1 = [1,2,3,4],
    arr2 = [2,4],
    res = arr1.filter(item => !arr2.includes(item));
console.log(res);
Hugolpz
  • 17,296
  • 26
  • 100
  • 187
Redu
  • 25,060
  • 6
  • 56
  • 76
  • 13
    Rockstar. Thank you, this was incredibly helpful for solving a slightly different problem. Filtering out an array of objects based on an array of values in a react component: ```const filteredResults = this.state.cards.filter( result => !this.state.filterOut.includes(result.category) )``` where this.state.cards in an array of objects and this.state.filterOut is an array of values that correspond the 'category' key in the objects that I wanted to remove. – Josh Pittman Jun 08 '17 at 08:07
  • 1
    I know, it's an older response, but I simply wanted to let you know that I liked this response a whole lot more and it helped me with one of my problems I had. It is very readable and thus it was easier for me to understand the issue better. – ak.leimrey May 24 '18 at 06:54
  • 1
    includes will only work from ES7. If you using ES6 use the accepted solution. – rudrasiva86 Jun 20 '18 at 16:24
  • 2
    Arrow functions FTW. Much nicer than the old school callback! – Davis Jones Sep 01 '20 at 19:43
  • Thank you very much, it really helped me a lot and I learned a new paradigm it's great thank you – 120DEV Nov 19 '22 at 15:28
209

You can use the this parameter of the filter() function to avoid to store your filter array in a global variable.

var filtered = [1, 2, 3, 4].filter(
    function(e) {
      return this.indexOf(e) < 0;
    },
    [2, 4]
);
console.log(filtered);
Mamun
  • 66,969
  • 9
  • 47
  • 59
Simon Hi
  • 2,838
  • 1
  • 17
  • 17
  • It works like a charm. Is it possible to move the function outside and call it in a more understandable way? Like: var filtered=[1,2,3,4].filter(myfunct(),[2,4]); – Robdll Jan 20 '16 at 16:00
  • 1
    Sure: var myFunct=function(e){return this.indexOf(e)<0;}; var filtered=[1,2,3,4].filter(myFunct,[2,4]); – Simon Hi Jan 20 '16 at 17:10
  • 1
    Can this be achieved with lambda expression in ES2016 or TypesScript? – Prabu Jun 30 '17 at 09:37
  • 1
    Angular version: https://stackblitz.com/edit/angular-wbynpf?embed=1&file=src/app/app.component.ts – Sunil Raj Oct 01 '18 at 07:06
  • When I use this approach, the second param of filter isn't making it into my function as `this`. `this` always seems to be undefined?! Weird – SomethingOn Jan 23 '19 at 15:12
  • @SomethingOn: did you put an array as second parameter? – Simon Hi Jan 24 '19 at 10:07
  • I did...the const was already defined before the filter anyway so I was able to reference it regardless. – SomethingOn Jan 24 '19 at 20:44
  • If you just add `const a = [2, 4];` at the beginning of the above code, and replace `[2, 4]` by `a` in the filter function, it seems working well. There is probably something else in your code that disturb the process. – Simon Hi Jan 29 '19 at 13:42
  • @SunilRaj sory but how is that the angular version. The angular version would deal with streams of data and filter with rxjs –  Nov 16 '19 at 14:46
76
var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallBack);

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

In the callback, you check if each value of array is in anotherOne

https://jsfiddle.net/0tsyc1sx/

If you are using lodash.js, use _.difference

filteredArray = _.difference(array, anotherOne);

Demo

If you have an array of objects :

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 array of objects

Demo diff array of objects with lodash

AshBringer
  • 2,614
  • 2
  • 20
  • 42
63

        /* 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
  • 1,243
  • 11
  • 20
30

If you need to compare an array of objects, this works in all cases:

let arr = [{ id: 1, title: "title1" },{ id: 2, title: "title2" }]
let brr = [{ id: 2, title: "title2" },{ id: 3, title: "title3" }]

const res = arr.filter(f => brr.some(item => item.id === f.id));
console.log(res);
arnaudjnn
  • 923
  • 10
  • 12
24

The code below is the simplest way to filter an array with respect to another array. Both arrays can have objects inside them instead of values.

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

Output: [3, 6]

Run_Script
  • 2,487
  • 2
  • 15
  • 30
Awais Jameel
  • 1,838
  • 19
  • 14
  • This is not filtering. The output is the array2. Why does this answer have 19 up votes? Doesn't makes sense. – Gass Nov 12 '21 at 06:23
18

All the above solutions "work", but are less than optimal for performance and are all approach the problem in the same way which is linearly searching all entries at each point using Array.prototype.indexOf or Array.prototype.includes. A far faster solution (far faster even than a binary search for most cases) would be to sort the arrays and skip ahead as you go along as seen below. However, one downside is that this requires all entries in the array to be numbers or strings. Also however, binary search may in some rare cases be faster than the progressive linear search. These cases arise from the fact that my progressive linear search has a complexity of O(2n1+n2) (only O(n1+n2) in the faster C/C++ version) (where n1 is the searched array and n2 is the filter array), whereas the binary search has a complexity of O(n1ceil(log2n2)) (ceil = round up -- to the ceiling), and, lastly, the indexOf search has a highly variable complexity between O(n1) and O(n1n2), averaging out to O(n1ceil(n2÷2)). Thus, indexOf will only be the fastest, on average, in the cases of (n1,n2) equaling {1,2}, {1,3}, or {x,1|x∈N}. However, this is still not a perfect representation of modern hardware. IndexOf is natively optimized to the fullest extent imaginable in most modern browsers, making it very subject to the laws of branch prediction. Thus, if we make the same assumption on indexOf as we do with progressive linear and binary search -- that the array is presorted -- then, according to the stats listed in the link, we can expect roughly a 6x speed up for IndexOf, shifting its complexity to between O(n1÷6) and O(n1n2), averaging out to O(n1ceil(n27÷12)). Finally, take note that the below solution will never work with objects because objects in JavaScript cannot be compared by pointers 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
    }
  };
}

Please see my other post here for more details on the binary search algorithm used

If you are squeamish about file size (which I respect), then you can sacrifice a little performance in order to greatly reduce the file size and increase maintainability.

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

To prove the difference in speed, let us examine some JSPerfs. For filtering an array of 16 elements, binary search is roughly 17% faster than indexOf while filterArrayByAnotherArray is roughly 93% faster than indexOf. For filtering an array of 256 elements, binary search is roughly 291% faster than indexOf while filterArrayByAnotherArray is roughly 353% faster than indexOf. For filtering an array of 4096 elements, binary search is roughly 2655% faster than indexOf while filterArrayByAnotherArray is roughly 4627% faster than indexOf.

Reverse-filtering (like an AND gate)

The previous section provided code to take array A and array B, and remove all elements from A that exist in B:

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

This next section will provide code for reverse-filtering, where we remove all elements from A that DO NOT exist in B. This process is functionally equivalent to only retaining the elements common to both A and B, like an AND gate:

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

Here is the code for reverse filtering:

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]
    ) {
        // 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
    }
  };
}

For the slower smaller version of the reverse filtering code, see below.

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;
    });
}
Dave Cole
  • 2,446
  • 2
  • 20
  • 26
Jack G
  • 4,553
  • 2
  • 41
  • 50
  • 7
    Thanks for your answer, I'm sure will be helpful for someone sooner or later, even if it should be used in edge cases (I.E. only when a performance problems raise up). In all other cases i'd suggest to use the maintainable / readable version. – Robdll Jun 14 '18 at 07:26
  • @koop4 This version is just as readable -- all you need to do is add in a few comments explaining that this method filters an array from all elements of another array. Also, extra performance never hurts (in fact, I would say it is good). Nevertheless, I do definitely agree that because this version is more complex, it is less maintainable than other solutions. – Jack G Jun 14 '18 at 15:12
  • 1
    @JackGiffin I think by readable he means mantainable and fast to read and understand by the average web developer, for when a change or simple understaning is needed. Great solution, just not for most cases. – zardilior Jul 06 '19 at 17:10
  • @zardilior Thank you for your input. I do indeed have a single-minded obsession with performance and it does indeed get in the way of my projects. I have tried to improve myself, but, alas, my obsession sometimes gets the better of me. Thank you for understanding and thank you for explaining your concern so clearly. – Jack G Jul 06 '19 at 17:33
  • 1
    @JackGiffin early optimization is one of the worst things for projects, performance should be applied generally in to ways, writing efficient code, if simple enough, meaning dont write straight through bad code, and when optimization is needed because performance doesn't meets requirements. So a person like you should work optimizing other projects that need that obsession derived skill. Hope it helps :) – zardilior Jul 06 '19 at 17:38
  • 1
    @zardilior It really does help. Thank you so much for your advice zardilior. I shall take it to heart and act upon it. – Jack G Jul 06 '19 at 17:46
  • 1
    @JackGiffin glad to be of service – zardilior Jul 06 '19 at 17:54
  • 1
    How does it will work if I'm trying to filter array by **not in** other array? – German Alzate Jun 30 '20 at 15:59
  • @GermanAlzate Excellent point. I added a new section to address that use case. – Jack G Jun 30 '20 at 18:02
  • 1
    @JackGiffin its great! but I it does looks like an 'intersection'. I was looking for some like remove all entries in array a that exists in array b: `diff([1, 2, 3], [3,4,5]) => [1,2]` – German Alzate Jun 30 '20 at 20:34
  • @GermanAlzate Please see my top original answer snippets: `filterArrayByAnotherArray([1,2,3], [3,4,5])` yields `[1,2]`. – Jack G Jun 30 '20 at 21:19
9

There are many answers for your question, but I don't see anyone using lambda expresion:

var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(x => anotherOne.indexOf(x) < 0);
Mati Cassanelli
  • 625
  • 6
  • 11
4

with object filter result

[{id:1},{id:2},{id:3},{id:4}].filter(v=>!([{id:2},{id:4}].some(e=>e.id === v.id)))

enter image description here

kuldeep chopra
  • 652
  • 9
  • 9
4

Here is how you can do it when the items in the arrays are objects.

The idea is to find the array of only the keys in an inner array using the map function

Then check if the array of those keys contain a specific element key in the outer array.

const existsInBothArrays = array1.filter((element1) =>
    array2.map((element2) => element2._searchKey).includes(element1._searchKey),
  );
Cryce Truly
  • 139
  • 1
  • 5
3

The OA can also be implemented in ES6 as follows

ES6:

 const filtered = [1, 2, 3, 4].filter(e => {
    return this.indexOf(e) < 0;
  },[2, 4]);
Hemadri Dasari
  • 32,666
  • 37
  • 119
  • 162
3

Below is an example

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]
Rahul Bhobe
  • 4,165
  • 4
  • 17
  • 32
Sagar M
  • 1,168
  • 13
  • 10
1

You can setup the filter function to iterate over the "filter array".

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
  • 59
  • 5
1

You can use the filter and then for the filter function use a reduction of the filtering array which checks and returns true when it finds a match then invert on return (!). The filter function is called once per element in the array. You are not doing a comparison of any of the elements in the function in your post.

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
  • 3,290
  • 1
  • 20
  • 24
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>
  • Thanks, it work, but i'd prefer to keep the local scope. Also the arr2 has a random number of elements. – Robdll Jan 20 '16 at 15:43
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>
1

A more flexible filtering array from another array which contain object properties

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
  • 2,161
  • 2
  • 20
  • 22
1

You can write a generic filterByIndex() function and make use of type inference in TS to save the hassle with the callback function:

let's say you have your array [1,2,3,4] that you want to filter() with the indices specified in the [2,4] array.

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

the byIndex function expects the element function and an array and looks like this:

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

result is then

filtered = [1,3]
lama
  • 362
  • 1
  • 2
  • 9
1

The solution of Jack Giffin is great but doesn't work for arrays with numbers bigger than 2^32. Below is a refactored, fast version to filter an array based on Jack's solution but it works for 64-bit arrays.

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
  • 69
  • 2
  • 7
1

It all depends on the type of array.

For simple arrays like arrays of strings. You can use the code as follows just like @Redu and @Hugolpz pointed out

 var arr1 = [1,2,3,4],
        arr2 = [2,4],
        res = arr1.filter(item => !arr2.includes(item));
    console.log(res);

Then for more complex array filters like filtering an array of objects from another array of object, you can use the code bellow

function filterArray(arr1, arr2) {
  return arr1.filter(item1 => !arr2.some(item2 => item1.id === item2.id));
}

OR

function filterArray(arr1, arr2) {
  const set = new Set(arr2.map(item => item.id));
  return arr1.reduce((filtered, item) => {
    if (!set.has(item.id)) {
      filtered.push(item);
    }
    return filtered;
  }, []);
}

Both of these methods are efficient and should work well even with large arrays. However, in case you have a huge amount of data, using a more performant data structure like Map or HashSet could be more optimal.

Map

function filterArray(arr1, arr2) {
  const map = new Map(arr2.map(item => [item.id, item]));
  return arr1.filter(item => !map.has(item.id));
}

Hashset

function filterArray(arr1, arr2) {
  const set = new Set(arr2.map(item => item.id));
  return arr1.filter(item => !set.has(item.id));
}
Godstrump
  • 74
  • 1
  • 1
  • 6
0

The following examples use new Set() to create a filtered array that has only unique elements:

Array with primitive data types: 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)));

Array with objects as items:

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
  • 402
  • 6
  • 10
0

I just want to give you an additional solution...

const arr1 = [1,2,3,4];
const arr2 = [2,4];
const container = arr2.reduce((res,item) => {
 res[item] = true;
 return res;
}, {});
const result = arr1.filter(item => !container[item]);

About the time complexity of above code: O(n). And,... we'll need more spaces (space complexity O(n)) => Trade-off... :))

0

if you want to filter an array with different structures with some matching properties you should do it like this.

let filteredArray = [];

array1.map(array1Item => {
array2.map(array2Item => {
  if (array1.property1 === array2.property2) {
    filteredArray.push(array1Item);
  }
});

this should make your life easy!

Muhammad Raqib
  • 304
  • 3
  • 12
-2

The best description to filter function is https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/Array/filter

You should simply condition function:

function conditionFun(element, index, array) {
   return element >= 10;
}
filtered = [12, 5, 8, 130, 44].filter(conditionFun);

And you can't access the variable value before it is assigned

suvroc
  • 3,058
  • 1
  • 15
  • 29