Home > Software engineering >  Filtering Two Arrays based on values to remove duplicates
Filtering Two Arrays based on values to remove duplicates

Time:04-16

I have two arrays that I am trying to filter specific values from them. In arr1 i have my intial dataset. in arr2 I have the items I want to delete from arr1.

The data in arr1 should only be deleted if it matches both the property's arr2.item and arr2.itemID

let arr1 = [
  { item: 'Apple', itemID: '8189', pricePaid: 0.0762235 },
  { item: 'Apple', itemID: '8188', pricePaid: 0.0762235 },
  { item: 'Pear', itemID: '7144', pricePaid: 1.0483152 },
  { item: 'Berry', itemID: '378', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '377', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '376', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '375', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '374', pricePaid: 0.002027 },
]


let arr2 = [
  { item: 'Berry', itemID: '378' },
  { item: 'Berry', itemID: '377' },
  { item: 'Berry', itemID: '376' },
  { item: 'Berry', itemID: '374' },
]

The code that I tried before was

const filtered_arr = arr2.map(i => JSON.stringify(i.item, i.itemID));
const NewItems = arr1.filter(i => !filtered_arr.includes(JSON.stringify(i.item, i.itemID)));
console.log(NewItems);

However, I am not getting the correct output.

The output I am looking for is:

[
  { item: 'Apple', itemID: '8189', pricePaid: 0.0762235 },
  { item: 'Apple', itemID: '8188', pricePaid: 0.0762235 },
  { item: 'Pear', itemID: '7144', pricePaid: 1.0483152 },
  { item: 'Berry', itemID: '375', pricePaid: 0.002027 },
]

Thank you for any help

CodePudding user response:

Your code doesn't have a chance because:

JSON.stringify(i.item, i.itemID)

is not used correctly. JSON.stringify() has a function signature like this:

JSON.stringify(value, replacer, space)

You can't just pass it two pieces of data like you were. You would have to combine those two pieces of data into an array or object before calling JSON.stringify() on that single object. but, as you will see in my second solution below, you don't need JSON to make a canonical representation of the two values that is directly comparable. Since they are both strings, you can just add them with a separator between them and then you can just directly compare the strings.


In my solutions to problems like this, I generally try to avoid NxM lookups when comparing multiple arrays by either using a Map or Set for more efficient lookup. A few lines more code than brute force searching, but a lot more efficient if the arrays get larger.

Here's one way, using a Map object for efficient lookup:

function filterArray(source, removals) {
    const removeMap = new Map(removals.map(entry => [entry.itemID, entry.item]));
    return source.filter(entry => {
        const match = removeMap.get(entry.itemID);
        return !match || match !== entry.item;
    });
}

let arr1 = [
  { item: 'Apple', itemID: '8189', pricePaid: 0.0762235 },
  { item: 'Apple', itemID: '8188', pricePaid: 0.0762235 },
  { item: 'Pear', itemID: '7144', pricePaid: 1.0483152 },
  { item: 'Berry', itemID: '378', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '377', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '376', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '375', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '374', pricePaid: 0.002027 },
]


let arr2 = [
  { item: 'Berry', itemID: '378' },
  { item: 'Berry', itemID: '377' },
  { item: 'Berry', itemID: '376' },
  { item: 'Berry', itemID: '374' },
]

console.log(filterArray(arr1, arr2));

And, a slightly shorter version using a Set for efficient lookup that combines the item and itemID into a single canonical string in a Set object:

function filterArray2(source, removals) {
    const removeSet = new Set(removals.map(entry => `${entry.item}-${entry.itemID}`));
    return source.filter(entry => !removeSet.has(`${entry.item}-${entry.itemID}`));
}

let arr1 = [
  { item: 'Apple', itemID: '8189', pricePaid: 0.0762235 },
  { item: 'Apple', itemID: '8188', pricePaid: 0.0762235 },
  { item: 'Pear', itemID: '7144', pricePaid: 1.0483152 },
  { item: 'Berry', itemID: '378', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '377', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '376', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '375', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '374', pricePaid: 0.002027 },
]


let arr2 = [
  { item: 'Berry', itemID: '378' },
  { item: 'Berry', itemID: '377' },
  { item: 'Berry', itemID: '376' },
  { item: 'Berry', itemID: '374' },
]

console.log(filterArray2(arr1, arr2));

This version just assumes that an itemID can't start with a - and an item name can't end with a -. If they could, then you just need a different separator character that isn't allowed at either the end of an item name or the start of an itemID.

CodePudding user response:

let arr1 = [
  { item: 'Apple', itemID: '8189', pricePaid: 0.0762235 },
  { item: 'Apple', itemID: '8188', pricePaid: 0.0762235 },
  { item: 'Pear', itemID: '7144', pricePaid: 1.0483152 },
  { item: 'Berry', itemID: '378', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '377', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '376', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '375', pricePaid: 0.002027 },
  { item: 'Berry', itemID: '374', pricePaid: 0.002027 },
]


let arr2 = [
  { item: 'Berry', itemID: '378' },
  { item: 'Berry', itemID: '377' },
  { item: 'Berry', itemID: '376' },
  { item: 'Berry', itemID: '374' },
]
let arr3=[];
arr2.filter((ele,ind)=>{
    arr1.filter((ele2,ind2)=>{
        if(ele.item===ele2.item && ele.itemID===ele2.itemID){
            arr3.push(arr1[ind2]);
        }
    })
})
console.log(arr3);

  • Related