Verwer
Verwer

Reputation: 13

Convert JS Array to a nested Object

What is the best way to convert:

['[Title A]','child A','child B', '[Title B]', 'child C', 'child D']

to:

{
  0: {
      'title': 'Title A',
      'children': ['child A', 'child B']
     }
  1: {
       'title': 'Title B',
       'children': ['Child C', 'Child D']
     }
}

I have this so far which checks on the presence of brackets [] and I tried to add this to an object with a dynamic index which increments during a for loop every time a title with brackets is found:

let index = 0;
let listObject = {};
for (const listItem of listItems) {
   const titleValue = listItem.match(/\[(.*?)\]/);
   if (titleValue) {
     ++index;
     listObject[index].title = titleValue[1];
   } else {
     listObject[index].children = [listItem];
   }
}

console.log(listObject);

Upvotes: 1

Views: 128

Answers (4)

Yasmin
Yasmin

Reputation: 343

For the sake of simplicity let's first make an array of objects:

const res = arr.reduce((acc, cur) => {
  const titleValue = cur.match(/\[(.*?)\]/)
  titleValue ?
    acc.push({
      title: cur,
      children: []
    }) :
    acc[acc.length - 1].children.push(cur)

  return acc
}, [])

Now you can use the spread operator to have the nested object:

{...res}

Upvotes: 1

Sunil Kumar
Sunil Kumar

Reputation: 420

const array = ['[Title A]','child A','child B', '[Title B]', 'child C', 'child D'];

let objToPush = {};
let objToSend = {};
array.map((d) => {
 if (/^\[[^\]]+\]$/.test(d)) {
  if (Object.keys(objToPush).length > 0) {
     objToSend[Object.keys(objToSend).length] = { ...objToPush };
     objToPush = {};
  }
  objToPush.title = d.substring(1, d.length - 1);
 } else {
  objToPush.children = objToPush.children ? [...objToPush.children, d] : [d]
 }
});
objToSend[Object.keys(objToSend).length] = { ...objToPush };
console.log('objToPush', objToSend);

it worked for me (JSFiddle https://jsfiddle.net/wepbzdfL/48/)

Upvotes: 0

Valentin Briand
Valentin Briand

Reputation: 3683

I don't know if it's the "best" way, but this is my solution:

const array = [
  "[Title A]",
  "child A",
  "child B",
  "[Title B]",
  "child C",
  "child D"
];

let index = -1;
const res = array.reduce((acc, curr) => {
  if (/^\[[^\]]+\]$/.test(curr)) {
    acc = {
      ...acc,
      [++index]: { title: curr.substring(1, curr.length - 1), children: [] }
    };
  } else {
    acc[index].children = [...acc[index].children, curr];
  }
  return acc;
}, {});

console.log(res);

Upvotes: 0

Marius
Marius

Reputation: 1574

Just updated yours so the logic is sound. Can see what you tried.

Read up on creating new objects and arrays in JS, and when you can add to them.

let listItems = ['[Title A]', 'child A', 'child B', '[Title B]', 'child C', 'child D'];

let index = 0;
var listObject = {};
for (const listItem of listItems) {
  const isTitle = listItem[0] == "[" && listItem[listItem.length - 1] == "]"
  if (isTitle) {
    ++index;
    listObject[index] = {
      title: listItem.substring(1, listItem.length -1),
      children: [] //Create Array
    }; //Create Object
  } else {
    listObject[index].children.push(listItem); //Add to children array
  }
}

console.log(listObject);

To add on why I used an index lookup, instead of regex,

Run this:

var testArray = [];

var arrayCount = 20000000;

var regexMatch = /\[(.*?)\]/;

for (var i = 0; i < arrayCount; i++) {
  testArray.push("[" + makeid(Math.round(Math.random() * 10)) + "]")
}

console.log(testArray.length);
var start = new Date();
console.log(start.toString());

for (var i = 0; i < arrayCount; i++) {
  var testItem = testArray[i];
  if (testItem.match(regexMatch)) {

  } else {

  }
}

console.log("regex took " + (new Date().getTime() - start.getTime()) / 1000 + " seconds");

start = new Date();
for (var i = 0; i < arrayCount; i++) {
  var testItem = testArray[i];
  if (testItem[0] === "[" && testItem[testItem.length - 1] === "]") {

  } else {

  }
}

console.log("index lookup took " + (new Date().getTime() - start.getTime()) / 1000 + " seconds");

function makeid(length) {
  var result = '';
  var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  var charactersLength = characters.length;
  for (var i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

Upvotes: 0

Related Questions