2

Given these two arrays:

const array1 = [
                {"id": 1, "color": "black"},
                {"id": 2, "color": "white"},
                {"id": 3, "color": "orange"}
               ];

const array2 = [
                {"id": 2, "color": "white"},
                {"id": 4, "color": "purple"}
               ];

How could I remove the duplicates from the first array if found in the second, i.e. the result would be:

const filtered = [
                  {"id": 1, "color": "black"},
                  {"id": 3, "color": "orange"}
                 ];

My code:

const filtered = array1.map(i => array2.filter(j => i["id"] !== j["id"]))

but it doesn't seem to work

Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
sfasfasd
  • 97
  • 1
  • 5
  • 1
    Possible duplicate of [How to filter an array from all elements of another array](https://stackoverflow.com/questions/34901593/how-to-filter-an-array-from-all-elements-of-another-array) – Andrew Lohr Sep 17 '19 at 16:00
  • Are duplicates considered by the `id` property, or by the combination of properties? For example, what would your expected behavior be if `array2` contained `{ "id": 3, "color": "blue" }` – Patrick Roberts Sep 17 '19 at 16:03
  • @AndrewLohr related, but not an exact duplicate. I'm sure there is one, but the answers for that one rely on the ability to compare elements of the array by value (rather than properties of each element). – Patrick Roberts Sep 17 '19 at 16:10

4 Answers4

3

To make your code work you can use filter and every

const array1 = [ {"id": 1, "color": "black"},{"id": 2, "color": "white"},{"id": 3, "color": "orange"}];
const array2 = [{"id": 2, "color": "white"},{"id": 4, "color": "purple"}];

const filtered = array1.filter(i => array2.every(j => i["id"] !== j["id"]))

console.log(filtered)

You can use Map and filter

const array1 = [ {"id": 1, "color": "black"},{"id": 2, "color": "white"},{"id": 3, "color": "orange"}];
const array2 = [{"id": 2, "color": "white"},{"id": 4, "color": "purple"}];

let mapper = new Map(array2.map(v=> [v.id,v]))

const final = array1.filter(({id})=> !mapper.has(id))

console.log(final)
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
0

We can use Array.prototype.filter to filter the first array. The filter condition can be constructed by various means having different time complexities:

  1. Linear time by using the Array.prototype.findIndex which will check if the current object is included in the second array:

const array1 = [{"id": 1, "color": "black"}, {"id": 2, "color": "white"}, {"id": 3, "color": "orange"}];
const array2 = [{"id": 2, "color": "white"}, {"id": 4, "color": "purple"}];

function filterArray(array1, array2,){
  return array1.filter( ({id}) => array2.findIndex((o) => id === o.id ) < 0);
}
console.log(filterArray(array1, array2));
  1. Or this can also be done efficiently by using a Set which has a constant time lookup:

const array1 = [{"id": 1, "color": "black"}, {"id": 2, "color": "white"}, {"id": 3, "color": "orange"}];
const array2 = [{"id": 2, "color": "white"}, {"id": 4, "color": "purple"}];

function filterArrayUsingSet(array1, array2){
  const lookup = new Set(array2.map(({id})  => id));
  return array1.filter( ({id}) => !lookup.has(id) );
}

console.log(filterArrayUsingSet(array1, array2));
  1. Even a Object literal can be used as a key lookup table, where the key will be the ids of array2 this will also be constant time lookup:

const array1 = [{"id": 1, "color": "black"}, {"id": 2, "color": "white"}, {"id": 3, "color": "orange"}];
const array2 = [{"id": 2, "color": "white"}, {"id": 4, "color": "purple"}];

function filterArrayUsingSet(array1, array2){
  const lookup = array2.reduce((acc, {id}) => {acc[id] = id; return acc}, {});
  return array1.filter( ({id}) => !(id in lookup));
}

console.log(filterArrayUsingSet(array1, array2));
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
0

If you want duplicates removed based on only 'id', you can do so using Array.filter() and Array.find() or Array.some() -

const filtered = array1.filter(x => !array2.find( y => y.id===x.id));

OR

const filtered = array1.filter(x => !array2.some( y => y.id===x.id));

Check this JS Bin to play around.

Vandesh
  • 6,368
  • 1
  • 26
  • 38
0

If you want to filter array based on any key-value match is found in second array, a solution using forEach and every:

function filterArray(arr1, arr2) {
    let filterArr = [];
    arr1.forEach(item => 
       arr2.every( val => val.id !== item.id && val.color !== item.color) && filterArr.push(item));

    return filterArr;
}