khizerrehandev
khizerrehandev

Reputation: 1535

Recursively filter nested json data using javascript or rxjs

I am looking to find elegant solution to filter nested json data structure so that filter functionality can be applied.

pre-condtions:

Thanks!!

e.g

   var dataToFilter = {
        "children": [{
            "tagPath": "/../../tagPath-1",
            "children": [{
                "tagPath": "/../../tagPath-1-1",
                "children": [{
                        "tagPath": "/../../tagPath-1-2",
                        "kind": "Y",
                        "children": [{
                                "tagPath": "/../../tagPath-1-3.1",
                                "kind": "X",
                                "children": []
                            },
                            {
                                "tagPath": "/../../tagPath-1.3.2",
                                "kind": "X",
                                "children": [{
                                    "tagPath": "/../../tagPath-1.3",
                                    "kind": "Y",
                                    "children": []
                                }]
                            }
                        ]
                    },
                    {
                        "kind": "Y",
                        "children": []
                    }
                ],
                "kind": "X",
            }],
            "kind": "Y",
        }]

Desired Output on kind property when value is e.g Y :

var desiredOutput = {
        "children": [{
            "tagPath": "/../../tagPath-1",
            "children": [{
                    "tagPath": "/../../tagPath-1-2",
                    "kind": "Y",
                    "children": [{
                        "tagPath": "/../../tagPath-1.3",
                        "kind": "Y",
                        "children": []
                    }]
                },
                {
                    "kind": "Y",
                    "children": []
                }
            ],
            "kind": "Y",
        }]
    ```

Upvotes: 1

Views: 518

Answers (1)

Yoshi
Yoshi

Reputation: 54649

You can use the following function:

const restructure = (nodes, filter) => nodes.reduce(
    (acc, node) => {
        const children = restructure(node.children, filter);

        return acc.concat(
            filter(node)
                ? {...node, children}
                : children
        );
    },
    []
);

Which accepts filter as a function. This allows you to decide how to filter, e.g.:

const yOnly = restructure(dataToFilter, node => 'Y' === node.kind);

Or:

const yAndX = restructure(dataToFilter, node => ['Y', 'X'].includes(node.kind));

The only difference to your code above is that dataToFilter must already be an array of nodes (see the full code snippet below).

const restructure = (nodes, filter) => nodes.reduce(
    (acc, node) => {
        const children = restructure(node.children, filter);

        return acc.concat(
            filter(node)
                ? {...node, children}
                : children
        );
    },
    []
);

const dataToFilter = [{
    'tagPath':  '/../../tagPath-1',
    'children': [{
        'tagPath':  '/../../tagPath-1-1',
        'children': [{
            'tagPath':  '/../../tagPath-1-2',
            'kind':     'Y',
            'children': [{
                'tagPath':  '/../../tagPath-1-3.1',
                'kind':     'X',
                'children': []
            }, {
                'tagPath':  '/../../tagPath-1.3.2',
                'kind':     'X',
                'children': [{
                    'tagPath':  '/../../tagPath-1.3',
                    'kind':     'Y',
                    'children': []
                }]
            }]
        }, {
            'kind':     'Y',
            'children': []
        }],
        'kind':     'X',
    }],
    'kind':     'Y',
}];

const yOnly = restructure(dataToFilter, node => 'Y' === node.kind);
const xOnly = restructure(dataToFilter, node => 'X' === node.kind);
const yAndX = restructure(dataToFilter, node => ['Y', 'X'].includes(node.kind));

console.log(yOnly);
console.log(xOnly);
console.log(yAndX);

Upvotes: 1

Related Questions