简体   繁体   中英

Filter nested array in object array by array of values

Considering below object array:

[
    {
        "guid": "j5Dc9Z",            
        "courses": [
            {
                "id": 1,
                "name": "foo",                    
            }
        ]
    },
    {
        "guid": "a5gdfS",
        "courses": [
            {
                "id": 2,
                "name": "bar",                    
            },
            {
                "id": 3,
                "name": "foo",                    
            },    
        ]
     },
     {
        "guid": "jHab6i",
        "courses": [
            {
                "id": 4,
                "name": "foobar",                    
            }   
        ]
     },  
     {...}    
]

I am trying to filter an object array, comparing IDs in the nested courses array with in the below array:

filter.courses = [1,3]

The following line works for the nth value in the array: (via https://stackoverflow.com/a/41347441/9766768 )

let fil = filter(this.results, { courses: [{ id: this.filter.courses[n] }]});

However, I'm hoping to achieve this (pseudo code below):

let fil = filter(this.results, { courses: [{ id: this.filter.courses }]});

Expected output would be an array of objects containing any of the course IDs elements, in this case:

[
    {
        "guid": "j5Dc9Z",            
        "courses": [
            {
                "id": 1,
                "name": "foo",                    
            }
        ]
    },
    {
        "guid": "a5gdfS",
        "courses": [
            {
                "id": 2,
                "name": "bar",                    
            },
            {
                "id": 3,
                "name": "foo",                    
            },    
        ]
     }   
]

What would be considered the best solution in this case? Avoiding loops would be a bonus.

If you're trying to filter the elements whose course IDs contain in the filter.courses , you may use Array#every and Array#includes to do that:

 const data = [{"guid":"j5Dc9Z","courses":[{"id":3,"name":"foo"}]},{"guid":"a5gdfS","courses":[{"id":1,"name":"bar"},{"id":3,"name":"foo"}]},{"guid":"jHab6i","courses":[{"id":7,"name":"foobar"}]}]; const courses = [1, 6, 3]; const r = data.filter(d => d.courses.every(c => courses.includes(c.id))); console.log(r);

try this,

 results = [ { "guid": "j5Dc9Z", "courses": [ { "id": 3, "name": "foo", } ] }, { "guid": "a5gdfS", "courses": [ { "id": 1, "name": "bar", }, { "id": 3, "name": "foo", }, ] } ] var filter = [1] console.log(results.map(result=>{ result.courses = result.courses.filter(course=>(filter.includes(course.id))) return result }))

Explore my recursive solution there: Playground Link

With this solution can nested array of objects being filtered from top level to botton level, layer by layer.

From what I understand the resulting array should contain all objects, that contain at least one course with an id that is contained in the array we use to filter.

So if an object exists with 2 courses - and one of them has an id we are looking for this object should then be part of the array that gets returned (see object with property "guid" : "a5gdfS" in the questions example)

With one little tweak the code provided in the answer by 31piy (marked as best by question owner) will do exactly what we desire. To do so we just change the array method every() to the array method some().

const r = data.filter(d => d.courses. every (c => courses.includes(c.id)));

const r = data.filter(d => d.courses. some (c => courses.includes(c.id)));

With the method every() the resulting array will only contain the objects, where each and every course has an id we are looking for. ("guid": "a5gdfS" is not in the resulting array)

With the method some() the resulting array will contain the objects, where at least one course has an id we are looking for ("guid": "a5gdfS" is in the resulting array)

 /* arrays are the same as provided in the question so that we can check against expected/desired output in the question */ const data = [{ "guid": "j5Dc9Z", "courses": [{ "id": 1, "name": "foo", }] }, { "guid": "a5gdfS", "courses": [{ "id": 2, "name": "bar", }, { "id": 3, "name": "foo", }, ] }, { "guid": "jHab6i", "courses": [{ "id": 4, "name": "foobar", }] } ]; const courses = [1, 3]; //array contains all objects with at least 1 course that has an id we are looking for const r = data.filter(d => d.courses.some(c => courses.includes(c.id))); console.log("code with some " + JSON.stringify(r)); //array contains only objects, whose classes all have an id we are looking for const o = data.filter(d => d.courses.every(c => courses.includes(c.id))); console.log("code with every " + JSON.stringify(o));

depending on what we are trying to do either every() or some() might be correct - depends on what we are trying to achieve

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