Home > Back-end >  Filter an array by checking the content of another array
Filter an array by checking the content of another array

Time:10-05

I have two arrays with the following structures:

const array1 = [{id: 1, name: "test"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}];
const array2 = [{weight: 1, ids: [1]}, {weight 3, ids: [3]}];

I want to filter array1 so that it only has items where the id does not exists within any of the ids arrays within array 2.

I tried the following:

array1.filter((item) =>
      !array1?.filter((item2) =>
        item2?.ids?.includes(item.id)
      )
    )

however it just returns an empty array.

Can anyone provide me with the correct way of doing this filtering?

CodePudding user response:

You can use array.every() to filter your array.

const array1 = [
  { id: 1, name: 'test' },
  { id: 2, name: 'test2' },
  { id: 3, name: 'test3' },
];
const array2 = [
  { weight: 1, ids: [1] },
  { weight: 3, ids: [3] },
];

const res = array1.filter((item1) =>
  array2.every((item2) => !item2.ids.includes(item1.id))
);

console.log(res)

CodePudding user response:

you need to find in array2 instead of filter array1

array1.filter((item)=>
!array2.find((item2)=>item2?.ids?.includes(items.id))
)

CodePudding user response:

You can flat array2 into a single array,and then use filter on array1

const array1 = [{id: 1, name: "test"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}];
const array2 = [{weight: 1, ids: [1]}, {weight:3, ids: [3]}];

let filters = array2.map(a => a.ids).flat()
let result = array1.filter(a => {
  return !filters.includes(a.id)
})
console.log(result)

CodePudding user response:

filter return a list where the callback return true and find return a item where the callback return true

array1.filter(({id})=>{
  return array2.find(({ids})=>ids.indexOf(id) == -1) == null
})

CodePudding user response:

Create a map that stores all the different ids from array2

const array1 = [{id: 1, name: "test"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}];
const array2 = [{weight: 1, ids: [2]}, {weight: 3, ids: [2]}];
const temp = array2.reduce((prev, {ids}) => {
    ids.forEach(id => {
        if(!prev.has(id)) {
            prev.set(id, true);
        }
    })
    return prev;
}, (new Map()));

Now filter from array1 based on the id not present in the map.

const ans = array1.filter(({id}) => !temp.has(id));
console.log(ans)

With map you will have better time complexity than what will be with array. (generally, add, delete, search all happen in O(1) with map)

CodePudding user response:

I think instead of a Map, the Set might be a better aggregator for keeping the list of existing ids. Set by default make the existing Ids list unique and Set.has method can be used to check if the id of the item from array1 exists in array2.


const existingIds = array2.reduce((list,item)=> {
   list = new Set([...list, ...item.ids])
   return list;
}, new Set())

array1.filter( ({id}) => !existingIds.has(id))

Benefits:

  • existingIds is Set so it will have each id only once.
  • Set.has a time complexity of O(1)
  • Total solution will have O(n) complexity
  • Related