5

I want to remove same object from array by comparing 2 arrays.

Sample Data:

arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
];

arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

let newArray = []; // new array with with no same values it should be unique.
arr1.map((val, i)=>{
   arr2.map((val2)=>{
    if(val.id == val2.id){
       console.log('Matched At: '+ i) // do nothing
    }else{
      newArray.push(val);
    }
   })
})
console.log(newArray); // e.g: [{id: 2, name: "b"}, {id: 3, name: "c"},];
2
  • Does this answer your question? Remove duplicate values from JS array Commented Mar 16, 2020 at 14:59
  • 1
    what if arr2 contains some unique elements to be merged? for example arr2 = [ {id: 1, name: "a"}, {id: 4, name: "d"}, {id: 5, name: "x"}, ] Commented Mar 16, 2020 at 15:52

8 Answers 8

7

Array.filter combined with not Array.some.

The trick here is also to not some,..

const arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
], arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

const newArray=arr1.filter(a=>!arr2.some(s=>s.id===a.id));

console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

As mentioned in comments the question could be interpreted slightly differently. If you also want the unqiue items from arr2, you basically just do it twice and join. IOW: check what not in arr2 is in arr1, and then check what not in arr1 that's in arr2.

eg..

const notIn=(a,b)=>a.filter(f=>!b.some(s=>f.id===s.id));
const newArray=[...notIn(arr1, arr2), ...notIn(arr2, arr1)];

Update 2: Time complexity, as mentioned by qiAlex there is loops within loops. Although some will short circuit on finding a match, if the dataset gets large things could slow down. This is were Set and Map comes in.

So to fix this using a Set.

const notIn=(a,b)=>a.filter(a=>!b.has(a.id));
const newArray=[
  ...notIn(arr1, new Set(arr2.map(m=>m.id))),
  ...notIn(arr2, new Set(arr1.map(m=>m.id)))
];
Sign up to request clarification or add additional context in comments.

5 Comments

what if arr2 contains some unique elements to be merged?
@qiAlex You mean like a unique merge? would need to confirm with OP on that one, for me I interpreted the question as return one array that does not contain another.
At first I undesrtand a question as like as you did, it is a fair assumption, but wasn't clearly specified by OP. it is also possible to understand a question as 2 arrays that should be transformed into a one excluding duplicates, but theoretically both arr1 and arr2 can contain unique items.
@qiAlex You can basically do it the same way, just do it twice and join. I'll update answer with this info.
In my scenario I didn't have unique values in arr2 so the answer worked perfectly.
2
const isInArray = (arr, id, name) => arr.reduce((result, curr) => ((curr.name === name && curr.id === id) || result), false)

const newArray = arr1.reduce((result, curr) => (isInArray(arr2, curr.id, curr.name) ? result : result.concat(curr)), [])

Comments

1

You can update you code using filter() method, instead of using .map() method like:

const arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
], arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

let newArray = []; // new array with with no same values it should be unique.
newArray = arr1.filter(function(a) {
    for(var i=0; i < arr2.length; i++){
      if(a.id == arr2[i].id) return false;
    }
    return true;
});
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

1

You check each element in first array whether its id lies in the second array by using Array.prototype.some. If the element is not present then only yield it.

const arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
];

const arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

const result = arr1.filter(x => !arr2.some(y => y.id === x.id));

console.log(result);

Comments

1

I think a simple comparer can works for getting differences and then concat them. with this method you dont need to check which array is bigger.

arr1 = [  {id: 1, name: "a"},  {id: 2, name: "b"},  {id: 3, name: "c"},  {id: 4, name: "d"}];

arr2 = [  {id: 1, name: "a"},  {id: 4, name: "d"},];

function localComparer(b){
  return function(a){
    return b.filter(
    function(item){
      return item.id == a.id && item.name == a.name
    }).length == 0;
  }
}

var onlyInArr1 = arr1.filter(localComparer(arr2));
var onlyInArr2 = arr2.filter(localComparer(arr1));

console.log(onlyInArr1.concat(onlyInArr2));

Comments

1

We can filter values by checking whether some element is not contained in current array:

const result = arr1.reduce((a, c) => {
  if (!arr2.some(a2 => a2.id === c.id))
      a.push(c);
  return a;
}, [])

An example:

let arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
];

let arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

const result = arr1.reduce((a, c) => {
  if (!arr2.some(a2 => a2.id === c.id))
      a.push(c);
  return a;
}, [])

console.log(result);

Comments

1

Try this one -

const arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
];

const arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

const arr3 = [...arr1, ...arr2];
const mySubArray = _.uniq(arr3, 'id');
console.log(mySubArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>

Comments

1

So many loops in every answer.

Complexity of the code my answer is 2N,

Idea is:

  1. to merge arrays.

  2. first loop - mark duplicates somehow

  3. second loop - filter duplicates out

arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
];

arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

let newArray = [...arr1, ...arr2].reduce((acc, item, index) => {
  acc.items.push(item);

  if (typeof acc.map[item.id] !== 'undefined') {
    acc.items[acc.map[item.id]] = null;
    acc.items[index] = null;
  }
  acc.map[item.id] = index;
  
  return acc
},  {map: {}, items: []}).items.filter(item => !!item)


console.log(newArray);

1 Comment

Complexity of the code my answer is 2N, Good point, if the dataset gets large, and performance is an issue doing this would be a good idea. Currently on this small dataset it's about 8X slower than a simple filter & some, but I don't think it would take much bigger dataset's before this gets faster. I'm up-voting this one for that reason. I suppose if performance is really paramount you could even do both by checking the lengths.. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.