ArthurJ
ArthurJ

Reputation: 849

How to filter object array based on various values within a json object

Given the following array of objects:

let list = [
    {id: 100, desc: 'Apple'},
    {id: 555, desc: 'Banana'},
    {id: 110, desc: 'Orange'},
    {id: 120, desc: 'Strawberry'}
]

and the following:

let myObj = {
    "res": {
        "myId": 555,
        "allIds": [
            {
                "subId": 100
            },
            {
                "subId": 120
            }
        ]
    }
}

I need to filter the list array above so that it doesn't include the myId value and any of the subId values within the allIds array.

So based on this requirement after filtering, I expect to only see the following remaining value within the list array, i.e.:

let list = [
    {id: 110, desc: 'Orange'}
]

as id: 110 doesn't equal myId and doesn't exist within the allIds array.

I tried the following which works for just myId:

let filteredArr = {list.filter((el) => el.id !== myObj.res.myId)}

but unsure how to also exclude/filter the subId's within the allIds array as well?

Upvotes: 0

Views: 751

Answers (2)

Insyte
Insyte

Reputation: 2236

You'll need to collate a list of ids that you want to filter out of your myObj object and simply filter the list. Something like this...

const blackList = [ myObj.res.myId, ...myObj.res.allIds.map(o => o.subId) ]
const filteredArr = list.filter(o => !blackList.includes(o.id))

console.log(filteredArr)

Upvotes: 2

T.J. Crowder
T.J. Crowder

Reputation: 1075755

I tried the following which works for just myId:

let filteredArr = {list.filter((el) => el.id !== myObj.res.myId)}

but unsure how to also exclude/filter the subId's within the allIds array as well?

First, those {...} around list.filter(...) don't belong there. The { after a = starts an object initializer, but that's not valid content for an object initializer.

Use && ("and") and then myObj.res.allIds.every to see if the subId of every element in myObj.res.allIds is not a match for el.id:

let filteredArr = list.filter(
    (el) => el.id !== myObj.res.myId && myObj.res.allIds.every(({ subId }) => subId !== el.id)
);

Live Example:

let list = [
    { id: 100, desc: "Apple" },
    { id: 555, desc: "Banana" },
    { id: 110, desc: "Orange" },
    { id: 120, desc: "Strawberry" },
];

let myObj = {
    res: {
        myId: 555,
        allIds: [
            {
                subId: 100,
            },
            {
                subId: 120,
            },
        ],
    },
};

let filteredArr = list.filter(
    (el) => el.id !== myObj.res.myId && myObj.res.allIds.every(({ subId }) => subId !== el.id)
);
console.log(filteredArr);

That's assuming that myObj.res.allIds is fairly short, so it's okay to re-traverse it for (nearly) every element of list. If it's not short, you might want to create a Set containing all of the disallowed id valuse (myObj.res.myId and the subId values) first, since lookup time for the has method of a Set is guaranteed to be sublinear (whereas every will be linear):

const disallowed = new Set([
    myObj.res.myId,
    ...myObj.res.allIds.map(({subId}) => subId),
]);
let filteredArr = list.filter((el) => !disallowed.has(el.id));

Live Example:

let list = [
    { id: 100, desc: "Apple" },
    { id: 555, desc: "Banana" },
    { id: 110, desc: "Orange" },
    { id: 120, desc: "Strawberry" },
];

let myObj = {
    res: {
        myId: 555,
        allIds: [
            {
                subId: 100,
            },
            {
                subId: 120,
            },
        ],
    },
};

const disallowed = new Set([
    myObj.res.myId,
    ...myObj.res.allIds.map(({subId}) => subId),
]);
let filteredArr = list.filter((el) => !disallowed.has(el.id));
console.log(filteredArr);

Upvotes: 2

Related Questions