Jm3s
Jm3s

Reputation: 617

Filter an array by checking the content of another array

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?

Upvotes: 0

Views: 74

Answers (6)

Salman ORAK
Salman ORAK

Reputation: 1

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

Upvotes: 0

KAMLESH KUMAR
KAMLESH KUMAR

Reputation: 130

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)

Upvotes: 0

SIHEM BOUHENNICHE
SIHEM BOUHENNICHE

Reputation: 436

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)

Upvotes: 2

diqye
diqye

Reputation: 74

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
})

Upvotes: 0

Wraithy
Wraithy

Reputation: 2056

you need to find in array2 instead of filter array1

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

Upvotes: 1

flyingfox
flyingfox

Reputation: 13506

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)

Upvotes: 1

Related Questions