Search code examples
javascripttypescriptlodash

Deep search list of objects with hierarchy


I have array of objects like this:

let items: MenuPath[] = [
            { title: "Archive", path: 'archive' },
            { title: "About", path: 'about' },
            { title: "Programs", path: 'programs', children: [{ title: 'Line with...', path: 'program-line' }] },
            {
                title: "Blog",
                path: 'blog',
                children: [
                    {
                        title: "Cars",
                        path: 'cars',
                        children: [
                            { title: 'Something about cars', path: 'smt-cars' },
                            {
                                title: 'Cars library',
                                path: 'cars-library',
                                children:  [
                                            { title: 'Line of horizon', path: 'line-horizon', children: [{ title: 'Something', path: 'smt-last' }] },
                                            { title: 'Lineup', path: 'lineup' },
                                        ]
                            }
                        ]
                    }
                ]
            }
        ];

And i need a function that will find all objects whose title contains "line" with full hierarchy

function searchAll(items, title){
 // ...
}

let result = [
   [ {title: "Programs", path: "programs"}, {title: "Line with...", path: 'program-line'} ], // path: /programs/program-line
   [ {title: "Blog", path: "blog"}, { title: "Cars", path: "cars" }, {title:"Cars library", path: "cars-library"}, {title: 'Line of horizon', path: 'line-horizon'} ], // path: /blog/cars/cars-library/line-horizon
   [ {title: "Blog", path: "blog"}, { title: "Cars", path: "cars" }, {title:"Cars library", path: "cars-library"}, {title: 'Lineup', path: 'lineup'} ], // path: /blog/cars/cars-library/lineup
];

How can this be done?


Solution

  • You can use recursion here, and a stack to keep track of the hierarchy.

    I've also made the search take a regex, as this works well for doing searches, eg. just putting /i at the end allowed for a case-insenstive search.

    ps: I've used structuredClone here just to make the snippet console look nicer, otherwise it create #refrences for duplicates.

    const items = [
        { title: "Archive", path: 'archive' },
        { title: "About", path: 'about' },
        { title: "Programs", path: 'programs', children: [{ title: 'Line with...', path: 'program-line' }] },
        {
            title: "Blog",
            path: 'blog',
            children: [
                {
                    title: "Cars",
                    path: 'cars',
                    children: [
                        { title: 'Something about cars', path: 'smt-cars' },
                        {
                            title: 'Cars library',
                            path: 'cars-library',
                            children: [
                                { title: 'Line of horizon', path: 'line-horizon', children: [{ title: 'Something', path: 'smt-last' }] },
                                { title: 'Lineup', path: 'lineup' },
                            ]
                        }
                    ]
                }
            ]
        }
    ];
    
    function searchAll(items, search){
        const stack = [];
        const results = [];
        function inner(items) {
            for (const i of items) {
                const {title, path} = i;
                stack.push({title,path})
                if (search.test(i.title))
                     results.push(structuredClone(stack));
                if (i.children) inner(i.children);
                stack.pop();
            }
        }
        inner(items);
        return results;
    }
       
    console.log(searchAll(items, /line/i))
    .as-console-wrapper { min-height: 100%!important; top: 0; }