1

I've tried modifying some of the similar solutions on here but I keep getting stuck, I believe I have part of this figured out however, the main caveat is that:

Some of the objects have extra keys, which renders my object comparison logic useless.

I am trying to compare two arrays of objects. One array is the original array, and the other array contains the items I want deleted from the original array. However there's one extra issue in that the second array contains extra keys, so my comparison logic doesn't work.

An example would make this easier, let's say I have the following two arrays:

const originalArray = [{id: 1, name: "darnell"}, {id: 2, name: "funboi"}, 
{id: 3, name: "jackson5"}, {id: 4, name: "zelensky"}];

const itemsToBeRemoved = [{id: 2, name: "funboi", extraProperty: "something"}, 
{id: 4, name: "zelensky", extraProperty: "somethingelse"}];

after running the logic, my final output should be this array:

[{id: 1, name: "darnell"}, {id: 3, name: "jackson5"}]

And here's the current code / logic that I have, which compares but doesn't handle the extra keys. How should I handle this? Thank you in advance.

const prepareArray = (arr) => {
  return arr.map((el) => {
    if (typeof el === "object" && el !== null) {
      return JSON.stringify(el);
    } else {
      return el;
    }
  });
};

const convertJSON = (arr) => {
  return arr.map((el) => {
    return JSON.parse(el);
  });
};

const compareArrays = (arr1, arr2) => {
  const currentArray = [...prepareArray(arr1)];
  const deletedItems = [...prepareArray(arr2)];
  const compared = currentArray.filter((el) => deletedItems.indexOf(el) === -1);
  return convertJSON(compared);
};
elguapo
  • 155
  • 1
  • 14

3 Answers3

4

How about using filter and some? You can extend the filter condition on select properties using &&.

const originalArray = [
  { id: 1, name: 'darnell' },
  { id: 2, name: 'funboi' },
  { id: 3, name: 'jackson5' },
  { id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
  { id: 2, name: 'funboi', extraProperty: 'something' },
  { id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
console.log(
  originalArray.filter(item => !itemsToBeRemoved.some(itemToBeRemoved => itemToBeRemoved.id === item.id))
)

Or you can generalise it as well.

const originalArray = [
  { id: 1, name: 'darnell' },
  { id: 2, name: 'funboi' },
  { id: 3, name: 'jackson5' },
  { id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
  { id: 2, name: 'funboi', extraProperty: 'something' },
  { id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
function filterIfSubset(originalArray, itemsToBeRemoved) {
  const filteredArray = [];
  for (let i = 0; i < originalArray.length; i++) {
    let isSubset = false;
    for (let j = 0; j < itemsToBeRemoved.length; j++) {
      // check if whole object is a subset of the object in itemsToBeRemoved
      if (Object.keys(originalArray[i]).every(key => originalArray[i][key] === itemsToBeRemoved[j][key])) {
        isSubset = true;
      }
    }
    if (!isSubset) {
      filteredArray.push(originalArray[i]);
    }
  }
  return filteredArray;
}
console.log(filterIfSubset(originalArray, itemsToBeRemoved));

Another simpler variation of the second approach:

const originalArray = [
  { id: 1, name: 'darnell' },
  { id: 2, name: 'funboi' },
  { id: 3, name: 'jackson5' },
  { id: 4, name: 'zelensky' },
];
const itemsToBeRemoved = [
  { id: 2, name: 'funboi', extraProperty: 'something' },
  { id: 4, name: 'zelensky', extraProperty: 'somethingelse' },
];
const removeSubsetObjectsIfExists = (originalArray, itemsToBeRemoved) => {
  return originalArray.filter(item => {
    const isSubset = itemsToBeRemoved.some(itemToBeRemoved => {
      return Object.keys(item).every(key => {
        return item[key] === itemToBeRemoved[key];
      });
    });
    return !isSubset;
  });
}
console.log(removeSubsetObjectsIfExists(originalArray, itemsToBeRemoved));
Parvesh Kumar
  • 1,104
  • 7
  • 16
  • Wow yeah this worked great. I thought I had tried this approach but I had my ! operator placed as itemToBeRemoved.id !== item.id. Huge brain fart. Thanks so much for your help sir you have genuinely made my night – elguapo Mar 02 '22 at 05:38
  • Didn't even think about the fact that I could add ! in front of itemsToBeRemoved. I just recently started learning javascript, should definitely spend more time practicing this type of logic :) – elguapo Mar 02 '22 at 05:41
  • In the first one you've to define each individual key, which you want to check. For e.g. I used Id comparison only and which can be extended on name too. Something like !itemsToBeRemoved.some(itemToBeRemoved => itemToBeRemoved.id === item.id && itemToBeRemoved.name === item.name)). Second one doesn't care how many keys are there. Let's say there are 100 items in your object. The code will become messy using first approach. – Parvesh Kumar Mar 02 '22 at 05:46
1

The example below is a reusable function, the third parameter is the key to which you compare values from both arrays.

Details are commented in example

const arr=[{id:1,name:"darnell"},{id:2,name:"funboi"},{id:3,name:"jackson5"},{id:4,name:"zelensky"}],del=[{id:2,name:"funboi",extraProperty:"something"},{id:4,name:"zelensky",extraProperty:"somethingelse"}];

/** Compare arrayA vs. delArray by a given key's value.
--- ex. key = 'id'
**/
function deleteByKey(arrayA, delArray, key) {
  /* Get an array of only the values of the given key from delArray
  --- ex. delList = [1, 2, 3, 4]
  */
  const delList = delArray.map(obj => obj[key]);
  
  /* On every object of arrayA compare delList values vs 
 current object's key's value
  --- ex. current obj[id] = 2
  --- [1, 2, 3, 4].includes(obj[id])
  Any match returns an empty array and non-matches are returned 
  in it's own array.
  --- ex. ? [] : [obj]
  The final return is a flattened array of the non-matching objects
  */
  return arrayA.flatMap(obj => delList.includes(obj[key]) ? [] : [obj]);  
};

console.log(deleteByKey(arr, del, 'id'));
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • Thank you for this and for the detailed comments! It's helped me learn quite a lot on how each step works. – elguapo Mar 02 '22 at 19:32
0

let ff = [{ id: 1, name: 'darnell' }, { id: 2, name: 'funboi' }, { id: 3, name: 'jackson5' }, { id: 4, name: 'zelensky' }]

let cc = [{ id: 2, name: 'funboi', extraProperty: 'something' },
 { id: 4, name: 'zelensky', extraProperty: 'somethingelse' }]
 let ar = []
 let out = []

const result =  ff.filter(function(i){
ar.push(i.id)
cc.forEach(function(k){
  out.push(k.id)
})
if(!out.includes(i.id)){
  // console.log(i.id, i)
  return i
 }
})
console.log(result)
Seun
  • 19
  • 5