How to do an array subtraction

7

Assuming I have an array

let arr1 = [
     {nome: 'Fulano', idade: 19}, 
     {nome: 'Ciclano',idade: 20}, 
     {nome: 'João',   idade: 20}, 
     {nome: 'Maria',  idade: 30}, 
     {nome: 'Teste',  idade: 52}
]

I have another

let arr2 = [
         {nome: 'Fulano', idade: 19}, 
         {nome: 'Ciclano',idade: 20}, 
]

How do I remove objects that are equal to arr1 from arr2 . For example, returning a new array:

let arr3 = [
             {nome: 'João',   idade: 20}, 
             {nome: 'Maria',  idade: 30}, 
             {nome: 'Teste',  idade: 52} 
    ]
    
asked by anonymous 23.02.2018 / 20:56

6 answers

8

Create an object arr3 equal to arr1 and loop arr2 by checking if it exists in arr1 . If it exists, remove from arr3 with splice . At the end you will have arr3 without the items you have in arr2 :

let arr1 = [
     {nome: 'Fulano', idade: 19}, 
     {nome: 'Ciclano',idade: 20}, 
     {nome: 'João',   idade: 20}, 
     {nome: 'Maria',  idade: 30}, 
     {nome: 'Teste',  idade: 52}
]

let arr2 = [
   {nome: 'Fulano', idade: 19}, 
   {nome: 'Ciclano',idade: 20}
]

let arr3 = arr1;

for(let it2 in arr2){
   for(let it1 in arr1){
      if(JSON.stringify(arr2[it2]) == JSON.stringify(arr1[it1])){
         arr3.splice(it1, 1);
         break; // se achou, não precisa continuar o loop
      }
   }
}

console.log(arr3);

Edit

Converted items into string for comparison as a whole, not values.

Edit 2

Another way using filter :

let arr1 = [
     {nome: 'Fulano', idade: 19}, 
     {nome: 'Ciclano',idade: 20}, 
     {nome: 'João',   idade: 20}, 
     {nome: 'Maria',  idade: 30}, 
     {nome: 'Teste',  idade: 52}
]

let arr2 = [
   {nome: 'Fulano', idade: 19}, 
   {nome: 'Ciclano',idade: 20}
]

const arr3 = arr1.filter( x => { 
  return JSON.stringify(arr2).indexOf(JSON.stringify(x)) < 0;
});

console.log(arr3);
    
23.02.2018 / 21:14
2

let arr1 = [       
 {nome: 'Fulano', idade: 19},         
 {nome: 'João',   idade: 20}, 
 {nome: 'Maria',  idade: 30},
 {nome: 'Ciclano',idade: 20},  
 {nome: 'Teste',  idade: 52}
];

let arr2 = [
  {nome: 'Ciclano',idade: 20},
  {nome: 'Fulano', idade: 19}
     
];

arr1 = arr1.filter( a1 => !arr2.filter( a2 => a1.nome == a2.nome).length);

console.log(arr1);

Explanation:

Array.filter ()

inside the first Array.filter it calls another Array.filter, for array 2 inside this Array.filter (the second) it checks if there is the same value in array 2, then with the length vc it takes the result of if that is 0 or 1 then the! in the first Array.filter will only catch if it is 0, in case if the name already exists in array 2 then it will not get that value;

    
23.02.2018 / 22:00
1

The quickest and easiest way is to convert the objects to a JSON string, compare them and perform the filter.

But if there are other needs like validate if all attributes and values are present on both sides and even in a different order the algorithm is getting more elaborate. And I have not tested this example with more complex objects.

Here's an example.

let arr1 = [       
     {nome: 'Fulano', idade: 19},         
     {nome: 'João',   idade: 20}, 
     {nome: 'Maria',  idade: 30},
     {nome: 'Ciclano',idade: 20},  
     {nome: 'Teste',  idade: 52}
]

let arr2 = [
  {nome: 'Ciclano',idade: 20},
  {nome: 'Fulano', idade: 19}
         
]

var removerItems = function(arrayOriginal, arrayFiltrar) {
  var filtro = arrayOriginal.slice();  
  
  for (var i = 0; i < arrayFiltrar.length; i++) {
    var itemBusca = arrayFiltrar[i];

    for (var j = 0; j < filtro.length; j++) {
      if (JSON.stringify(filtro[j]) === JSON.stringify(itemBusca)){
        filtro.splice(j,1);        
      }
    }    
  }
  
  return filtro;
}

console.log(removerItems(arr1, arr2));
    
23.02.2018 / 21:47
1

You can use differenceWith method of library Lodash .

let arr1 = [
   {nome: 'Fulano', idade: 19}, 
   {nome: 'Fulano', idade: 39}, 
   {nome: 'Ciclano',idade: 20}, 
   {nome: 'João',   idade: 20}, 
   {nome: 'Maria',  idade: 30}, 
   {nome: 'Teste',  idade: 52}
]

let arr2 = [
   {nome: 'Fulano', idade: 19}, 
   {nome: 'Ciclano',idade: 20}
]
let arr3 = _.differenceWith(arr1, arr2, _.isEqual);
console.log(arr3)
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
    
24.02.2018 / 01:26
0

A simpler way to do is, first, you should find the index of the element you want to remove:

var array = [2, 5, 9];
var index = array.indexOf(5);

Then you can remove the element, if found, using the splice method:

if (index > -1) {
    array.splice(index, 1);
}

In your case, since it is a two-dimensional array you can use the following function to get the index as you go through the second array:

findIndex(x => x.nome == 'Ciclano')
    
23.02.2018 / 21:14
0

I created a function that gets two lists of objects and one property, how it works:

For each iteration of the first list I go through the second one comparing the received property, if this property does not exist in the second list then I add in a third list that after all the iterations will be the one returned by the function.

Example:

function subtraiArray(arr1, arr2, prop){
  let arr3 = [];
  var existe;
  for(i=0;i<arr1.length;i++){
    existe = false;
    for(j=0;j<arr2.length;j++){
      if(arr1[i][prop] == arr2[j][prop]){
        existe = true;
        break;
      }
    }

    //Caso o nome dessa posição não exista no segundo array eu insiro
    if(!existe)
      arr3.push(arr1[i]);
  }
  
  return arr3;
}

let arr1 = [{nome: 'Fulano', idade: 19},{nome: 'Ciclano',idade: 20},{nome: 'João',   idade: 20},{nome: 'Maria',  idade: 30},{nome: 'Teste',  idade: 52}];

let arr2 = [{nome: 'Fulano', idade: 19},{nome: 'Ciclano',idade: 20}];

console.log(subtraiArray(arr1, arr2, "nome"));
    
23.02.2018 / 21:19