filter array of objects by another array of objects

后端 未结 4 1951
日久生厌
日久生厌 2020-12-08 23:22

I want to filter array of objects by another array of objects.

I have 2 array of objects like this:

const array = [
    { id: 1, name: \'a1\', sub: {         


        
相关标签:
4条回答
  • 2020-12-08 23:55

    You can use Array.filter and then Array.some since the later would return boolean instead of the element like Array.find would:

    const a1 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } }, { id: 4, name: 'a4', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ]; 
    const a2 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ];
    
    const result = a1.filter(({id, sub}) => !a2.some(x => x.id == id) && sub)
    
    console.log(result)

    0 讨论(0)
  • 2020-12-08 23:56

    Ok, let's solve this step by step.

    To simplify the process let's suppose that two elements can be considered equals if they both have the same id.

    The first approach that I would use is to iterate the first array and, for each element, iterate the second one to check the conditions that you've defined above.

    const A = [ /* ... */]
    const B = [ /* ... */]
    
    A.filter(el => {
      let existsInB = !!B.find(e => {
        return e.id === el.id
      }
    
      return existsInB && !!B.sub
    })
    

    If we are sure that the elements in A and in B are really the same when they have the same ID, we could skip all the A elements without the sub property to perform it up a little bit

    A.filter(el => {
      if (!el.sub) return false
    
      let existsInB = !!B.find(e => {
        return e.id === el.id
      }
    
      return existsInB
    })
    

    Now, if our arrays are bigger than that, it means that we are wasting a lot of time looking for the element into B. Usually, in these cases, I transform the array where I look for into a map, like this

    var BMap = {}
    B.forEach(el => {
      BMap[el.id] = el
    })
    
    A.filter(el => {
      if (!el.sub) return false
    
      return !!BMap[el.id]
    })
    

    In this way you "waste" a little bit of time to create your map at the beginning, but then you can find your elements quicker.

    From here there could be even more optimizations but I think this is enought for this question

    0 讨论(0)
  • 2020-12-09 00:02

    You could use JSON.stringify to compare the two objects. It would be better to write a function that compares all properties on the objects recursively.

    const array = [
        { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
        { id: 2, name: 'a2', sub: null },
        { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
        { id: 4, name: 'a4', sub: null },
        { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
    ];
    const anotherArray = [
        { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
        { id: 2, name: 'a2', sub: null },
        { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
    ];
    
    const notIn = (array1, array2) => array1.filter(item1 => {
        const item1Str = JSON.stringify(item1);
        return !array2.find(item2 => item1Str === JSON.stringify(item2))
      }
    );
    
    console.log(notIn(array, anotherArray));

    0 讨论(0)
  • 2020-12-09 00:09

    Like Felix mentioned, Array#filter won't work faster than native for loop, however if you really want it as functional way, here's one possible solution:

    const array = [
        { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
        { id: 2, name: 'a2', sub: null },
        { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
        { id: 4, name: 'a4', sub: null },
        { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
    ];
    
    const anotherArray = [
        { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
        { id: 2, name: 'a2', sub: null },
        { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
    ];
    
    const r = array.filter((elem) => !anotherArray.find(({ id }) => elem.id === id) && elem.sub);
    
    console.log(r);

    0 讨论(0)
提交回复
热议问题