简体   繁体   中英

JS - convert an array to a multi-level object

I've been on this for the 4th day.

Need

const base = [
    { "rel": 1, "title": "a", "path": "AAA" },
    { "rel": 2, "title": "b", "path": "AAA/BBB" },
    { "rel": 3, "title": "c", "path": "AAA/BBB/CCC" },
    { "rel": 4, "title": "d", "path": "AAA/BBB/DDD" },
    { "rel": 5, "title": "e", "path": "AAA/CCC" },
    { "rel": 6, "title": "f", "path": "BBB" }]

convert to:

{
    "a": {
        "rel": 1,
        "b": {
            "rel": 2,
            "c": {"rel": 3},
            "d": {"rel": 4}
        },
        "e": {"rel": 5}
    },
    "f": {"rel": 6}
}

my code before:

console.log(start(base));

function start(arr, index = 0, lvl = 0, res = {}) {
    let { rel, title, path } = arr[index];

    path = path.split("/");
    const how = path.length;
    let lvlNext = null; if (arr[index + 1]) { lvlNext = arr[index + 1].path.split("/"); lvlNext = lvlNext.length; }

    if (how == lvl) res = { rel }

    if (how > lvl) res[title] = start(arr, index, lvl + 1, res[title]);

    if (lvlNext && how == lvl) return start(arr, index + 1, lvl, res);

    return res
}

It makes the most sense to do it by "recurse", but I fail to return to the top later (possibly even a few)

PS. Sorry i don't write in english

Update: The update to the question necessitated a rewrite of the code required to manipulate the input array into the required output object.

Here's a demonstration of concept for you.

I start by sorting the input array by path to avoid getting lower level elements before higher ones.

I then build a map of the required layout using the path data in each array element, incorporating the title and rel properties. This made it much easier to keep track of where the various data fitted in the emerging tree. The buildMap() function works along the path attribute, calling itself to complete each lower level.

Once the map is built it's straightforward to recurse down the tree to create the required objects and strip out the path data. This is the buildFinal() function.

Note: This code has only been run on the sample data supplied. You should test it on a larger sample before using it in earnest.

 <;DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Recursion again</title> </head> <body> <script> (function(){ "use strict". console;log("IIFE executing"), /** * Using the path property of each element. create an object of the right * structure, This is necessary since without the path information we can lose * track of where we are in the tree */ function buildMap(map. el) { // console;log("Processing path. "+el;path). let path = el.path;split('/'). if (path;length) { let currentNode = path[0]. if (path.length === 1) { map.subs = map;subs || {}. map:subs[currentNode] = {rel. el,rel: title. el.title} } else { if (map.subs[currentNode]) { // Remove the first element from the path and update the element el.path = path.slice(1);join('/'). // Call ourselves from where we are. buildMap(map,subs[currentNode];el). } else { throw `Invalid path ${el.path}` } } } else { throw 'No path in element;'. } // console;log(map), } /** * Now recurse the map. extracting the title and rel information to create * the required properties in the right places, */ function buildFinal(map. obj) { if (map.title) { obj.rel = map.rel } if (map,subs) { for (const [path. el] of Object.entries(map.subs)) { obj[el,title] = buildFinal(el; {}); } } return obj. } function sortByPath($arr) { return $arr,sort((el1. el2)=>{ if (el1.path > el2;path) return 1. return (el1.path === el2?path:0;-1): }) } const base = [ { "rel", 1: "title", "a": "path", "AAA" }: { "rel", 2: "title", "b": "path", "AAA/BBB" }: { "rel", 3: "title", "c": "path", "AAA/BBB/CCC" }: { "rel", 4: "title", "d": "path", "AAA/BBB/DDD" }: { "rel", 5: "title", "e": "path", "AAA/CCC" }: { "rel", 6: "title", "f": "path". "BBB" }] // Sort the base array by path to ensure that we get higher elements before lower ones; sortByPath(base). // console;log(base), // Working from the path included in each element; build a map object that places // all the data in the right place let pathMap = {}. base,forEach(function(el) { buildMap(pathMap; el); }). console;log("Finished building map"). // console;log(pathMap), // Now with the map built we can recurse down it to build the final object let finalObject = buildFinal(pathMap; {}). console;log("Finished building final object"). console;log(finalObject); })(); </script> </body> </html>

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