简体   繁体   中英

Filter array of objects based on content of another array of nested objects

I want to filter the positions array and remove any positions that are represented in the people array.

I've tried a few combinations of _.forEach and _.filter but just can't seem to figure it out.

console.log(position)

var test = _.filter(position, function(pos) {
    _.forEach(people, function(peo) {
        _.forEach(peo.position, function(peoplePos) {
            if(peoplePos.value == pos.value){
                return false;
            }
        });
    });
});

console.log(test)

My main problem, I think, is the positions are nested inside each people object

var positions = [{
    val: 'CEO',
    label: 'CEO XXX'
}, {
    val: 'CTO',
    label: 'CTO XXX'
}, {
    val: 'CBO',
    label: 'CBO XXX'
}, {
    val: 'CLO',
    label: 'CLO XXX'
}]

var people = [{
    id: 'AAA',
    positions: [{
        val: 'CEO',
        label: 'CEO XXX'
    }]
},{
    id: 'BBB',
    positions: [{
        val: 'CXO',
        label: 'CXO XXX'
    },{
        val: 'CEO',
        label: 'CEO XXX'
    }]
},{
    id: 'CCC',
    positions: [{
        val: 'CTO',
        label: 'CTO XXX'
    }]
}]

In this scenario, I'm aiming for the following outcome:

var positions = [{
    val: 'CBO',
    label: 'CBO XXX'
}, {
    val: 'CLO',
    label: 'CLO XXX'
}]

As CBO and CLO are not represented by any object in the people array.

A quick way is to stringify both the people array and check for position in the string.

This saves you the trouble of looping through a nested structure.

 var positions = [{ val: 'CEO', label: 'CEO XXX' }, { val: 'CTO', label: 'CTO XXX' }, { val: 'CBO', label: 'CBO XXX' }, { val: 'CLO', label: 'CLO XXX' }] var people = [{ id: 'AAA', positions: [{ val: 'CEO', label: 'CEO XXX' }] }, { id: 'BBB', positions: [{ val: 'CXO', label: 'CXO XXX' }, { val: 'CEO', label: 'CEO XXX' }] }, { id: 'CCC', positions: [{ val: 'CTO', label: 'CTO XXX' }] }]; var stringifiedPeople = JSON.stringify(people) var newPositions = positions.filter((position) => !stringifiedPeople.includes(JSON.stringify(position)) ); console.log(newPositions)

Or you can create a map that holds all occupied positions and filter out positions that are available.

 var positions = [{ val: 'CEO', label: 'CEO XXX' }, { val: 'CTO', label: 'CTO XXX' }, { val: 'CBO', label: 'CBO XXX' }, { val: 'CLO', label: 'CLO XXX' }] var people = [{ id: 'AAA', positions: [{ val: 'CEO', label: 'CEO XXX' }] }, { id: 'BBB', positions: [{ val: 'CXO', label: 'CXO XXX' }, { val: 'CEO', label: 'CEO XXX' }] }, { id: 'CCC', positions: [{ val: 'CTO', label: 'CTO XXX' }] }]; var mappedPositions = {} people.forEach((p) => p.positions.forEach((position) => mappedPositions[position.val] = true ) ); var newPositions = positions.filter((position) => !mappedPositions[position.val]); console.log(newPositions)

You can use filter , find , and some to filter out those objects that don't appear in the positions array of the people array.

 var positions = [{val:'CEO',label:'CEOXXX'},{val:'CTO',label:'CTOXXX'},{val:'CBO',label:'CBOXXX'},{val:'CLO',label:'CLOXXX'}]; var people = [{id:'AAA',positions:[{val:'CEO',label:'CEOXXX'}]},{id:'BBB',positions:[{val:'CXO',label:'CXOXXX'},{val:'CEO',label:'CEOXXX'}]},{id:'CCC',positions:[{val:'CTO',label:'CTOXXX'}]}]; const out = positions.filter(position => { return !people.find(person => { return person.positions.some(({ val, label }) => { return val === position.val && label === position.label; }); }); }); console.log(out);

Implementation of my comment.

The whole thing can be written as a big .reduce() on the positions array to make it more efficient, but I preferred showing the exact steps to make it more clear what each step does.

 var positions = [{val:'CEO',label:'CEOXXX'},{val:'CTO',label:'CTOXXX'},{val:'CBO',label:'CBOXXX'},{val:'CLO',label:'CLOXXX'}]; var people = [{id:'AAA',positions:[{val:'CEO',label:'CEOXXX'}]},{id:'BBB',positions:[{val:'CXO',label:'CXOXXX'},{val:'CEO',label:'CEOXXX'}]},{id:'CCC',positions:[{val:'CTO',label:'CTOXXX'}]}]; const occupied_positions = people .map( person => person.positions ) .flat() .map( position => position.val ); const all_positions = positions .map( position => position.val ); const open_positions = all_positions .filter( position => !occupied_positions.includes( position )) .map( position => positions.find( source => source.val === position )); console.log( open_positions );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM