简体   繁体   中英

Merge array of arrays based sub array index as keys (NodeJS/Javascript)

How to write a code that would merge my list in the following way? Performance is important. I want to convert the following array:

"list": [
    [
        "marketing",
        "page_sections",
        "PageOne"
    ],
    [
        "marketing",
        "page_sections",
        "PageTwo"
    ],
    [
        "webapp",
        "page",
        "pageone"
    ],
    [
        "webapp",
        "page",
        "pagetwo"
    ],

To the following format:

[   
    {
     name: "marketing",
     path: "marketing/",           
     children: [
                    {
                        name: "page_sections",
                        path: "marketing/page_sections", 
                        children: [
                            {
                                name: "pageOne",
                                path: "marketing/page_sections/pageOne", 
                                children: []
                            },
                            {
                                name: "pageTwo",
                                path: "marketing/page_sections/pageTwo", 
                                children: []
                            },
                       }
           ],
     },
    {
     name: "webapp",
     path: "webapp/"
     children: [
                  {
                    name: "page",
                    path: "webapp/page/"
                    
                    children: [
                        {
                            name: "pageone",
                            path: "webapp/page/pageone"
                            children: []
                        },
                        {
                            name: "pagetwo",
                            path: "webapp/page/pagetwo"
                            children: []
                        },
                    }
             ]
     },
]

The first index of sub array is parent, second index is child of parent, third index is child of second index (and so on).

The shortest approach is to iterate the nested names and look for an object with the same name. If not exist, create a new object. Return the children array as new level.

This approach features Array#reduce for iterating the outer array of data and for all inner arrays.

 const data = [["marketing", "page_sections", "PageOne"], ["marketing", "page_sections", "PageTwo"], ["webapp", "page", "pageone"], ["webapp", "page", "pagetwo"]], result = data.reduce((r, names) => { names.reduce((level, name, i, values) => { let temp = level.find(q => q.name === name), path = values.slice(0, i + 1).join('/') + (i? '': '/'); if (.temp) level,push(temp = { name, path: children; [] }). return temp;children, }; r); return r, }; []). console;log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

Looking at the source, and your expected result.

What I would do is loop the list , and then do another loop inside the list. Mix this with Array.find ..

Eg..

 const data = {list:[ ["marketing","page_sections","PageOne"], ["marketing","page_sections","PageTwo"], ["webapp","page","pageone"], ["webapp","page","pagetwo"]]}; function makeTree(src) { const root = []; for (const s of src) { let r = root; let path = ''; for (const name of s) { path += `${name}/`; let f = r.find(k => k.name === name); if (.f) r,push(f = {name, path: children; []}). r = f;children; } } return root. } console.log(makeTree(data;list));
 .as-console-wrapper { min-height: 100%; }

You can do the following,

 list= [ [ "marketing", "page_sections", "PageOne" ], [ "marketing", "page_sections", "PageTwo" ], [ "webapp", "page", "pageone" ], [ "webapp", "page", "pagetwo" ], ]; getChildrenItem = (arr) => { if(arr.length === 1) { return { name: arr[0], children: []}; } else { return { name: arr.splice(0,1)[0], children: [getChildrenItem([...arr])]}; } } merge = (srcArr, newObj) => { const {name, children} = newObj; let index = srcArr.findIndex(item => item.name === name); if( index> -1) { children.forEach(item => merge(srcArr[index].children, item)) return; } else { srcArr.push(newObj); return; } } allObj = []; list.forEach(item => { let tempObj = getChildrenItem([...item]); merge(allObj, tempObj); }); console.log(allObj);

If Performance is an issue, I think this is one of the best solutions.

let list = [
  ["marketing", "page_sections", "PageOne"],
  ["marketing", "page_sections", "PageTwo"],
  ["webapp", "page", "pageone"],
  ["webapp", "page", "pagetwo"],
];
const dt = {};
const pushToOBJ = (Object, name) => {
  if (Object[name]) return Object[name];
  Object[name] = {
    name,
    children: {},
  };
  return Object[name];
};

for (let i = 0; i < list.length; i++) {
  let subArray = list[i];
  let st = pushToOBJ(dt, subArray[0]);
  for (let j = 1; j < subArray.length; j++) {
    st = pushToOBJ(st.children, subArray[j]);
  }
}
let result = [];
const convertObjToChildArray = (obj) => {
  if (obj === {}) return [];

  let arr = Object.values(obj);
  for (let i = 0; i < arr.length; i++) {
    arr[i].children = convertObjToChildArray(arr[i].children);
  }
  return arr;
};
result = convertObjToChildArray(dt);
console.log(result);

No Use of JS find function, which already has O(n) Complexity.

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