Home > Software engineering >  manipulate nested array of objects to access children values
manipulate nested array of objects to access children values

Time:07-04

I have a nested array of objects:

const nestArray = [
   {
      title: "title 1",
      children: [
         {
            title: "title 1-1",
            children: [
               { title: "title 1-1-1", children: [...] },
               { title: "title 1-1-2", children: [...] }
            ]
         },
         {
            title: "title 1-2",
            children: [
               { title: "title 1-2-1", children: [...] },
               { title: "title 1-2-2", children: [...] }
            ]
         },
      ]
   },
   {...},
   {...}
]

All objects have the same interface:

interface Obj {
   title: string
   children: Obj[]
}

I need to put a new key into each object called keys. The keys will keep all its children's titles alongside its own title. So the final result should be:

const nestArray = [
   {
      title: "title 1",
      keys: ["title 1", "title 1-1", "title 1-1-1", "title 1-1-2"],
      children: [
         {
            title: "title 1-1",
            keys: ["title 1-1", "title 1-1-1", "title 1-1-2"],
            children: [
               { title: "title 1-1-1", keys: ["title 1-1-1"], children: [] },
               { title: "title 1-1-2", keys: ["title 1-1-2"], children: [] }
            ]
         },
         {
            title: "title 1-2",
            keys: ["title 1-2", "title 1-2-1", "title 1-2-2"],
            children: [
               { title: "title 1-2-1", keys: ["title 1-2-1"], children: [] },
               { title: "title 1-2-2", keys: ["title 1-2-2"], children: [] }
            ]
         },
      ]
   },
   {...},
   {...}
]

so the interface will be changed as:

interface Obj {
   title: string
   children: Obj[]
   keys: string[]
}

I searched a lot but couldn't find any solution on the internet. I tried to solve this problem on my own, using recursive functions but still, I couldn't do it.

Using lodash is fine

What i've tried so far:

const mapTitlesToKeys = (obj) => {
  obj.keys = [obj.title];
  obj.children.forEach((childObj) => {
    mapTitlesToKeys(childObj);
    obj.keys.push(childObj.title);
  });
};

nestArray.forEach((obj) => {
  mapTitlesToKeys(obj);
});

console.log(nestArray);

results in:

[
   {
      title: "title 1",
      keys: ['title 1', 'title 1-1', 'title 1-2'], // <-- should be ["title 1", "title 1-1", "title 1-1-1", "title 1-1-2"]
      children: [
         {
            title: "title 1-1",
            keys: ['title 1-1', 'title 1-1-1', 'title 1-1-2'], // <-- should be ["title 1-1", "title 1-1-1", "title 1-1-2"]
            children: [
              {
                title: "title 1-1-1",
                keys: ["title 1-1-1"], // <-- fine
                children: []
              },
              {
                title: "title 1-1-2",
                keys: ["title 1-1-2"], // <-- fine
                children: []
              }
            ]
         },
         {
            title: "title 1-2",
            keys:  ['title 1-2', 'title 1-2-1', 'title 1-2-2'], // <-- should be ["title 1-2", "title 1-2-1", "title 1-2-2"] 
            children: [
              {
                title: "title 1-2-1",
                keys: ["title 1-2-1"], // <-- fine
                children: []
              },
              {
                title: "title 1-2-2",
                keys: ["title 1-2-2"], // <-- fine
                children: []
              }
            ]
         },
      ]
   },
   {...},
   {...}
]

CodePudding user response:

Presented below is one possible way to achieve the desired objective.

Code Snippet

const addKeysTo = arr => (
  arr.map(
    ({ title, children }) => {
      const cArr = addKeysTo(children);
      keys = [title, ...cArr.flatMap(({ keys }) => keys )];
      return ({ title, keys, children: cArr });
    }
  )
);
/* explanation of the method
// method to add "keys" array to each elt
const addKeysTo = arr => (
  // use ".map()" to iterate over given array
  arr.map(
    // destructure to access "title", "children"
    ({ title, children }) => {
      // recurse to obtain updated childre-narray
      const cArr = addKeysTo(children);
      // construct "keys" array for current elt
      keys = [title, ...cArr.flatMap(({ keys }) => keys )];
      // explicit return of current elt of "arr" array with "keys" prop
      return ({ title, keys, children: cArr });
    }
  )   // implicit return from the method
);
*/
const nestArray = [{
  title: "title 1",
  children: [{
      title: "title 1-1",
      children: [{
          title: "title 1-1-1",
          children: []
        },
        {
          title: "title 1-1-2",
          children: []
        }
      ]
    },
    {
      title: "title 1-2",
      children: [{
          title: "title 1-2-1",
          children: []
        },
        {
          title: "title 1-2-2",
          children: []
        }
      ]
    },
  ]
}];

console.log(
  'added keys to nested-objects array...\n',
  addKeysTo(nestArray)
);
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Inline comments added to the snippet above.

CodePudding user response:

Something like this? (Shorter version... No need to keep the old one)

const nestArray = [{
  title: "title 1",
  children: [{
      title: "title 1-1",
      children: [{
          title: "title 1-1-1",
          children: []
        },
        {
          title: "title 1-1-2",
          children: []
        }
      ]
    },
    {
      title: "title 1-2",
      children: [{
          title: "title 1-2-1",
          children: []
        },
        {
          title: "title 1-2-2",
          children: []
        }
      ]
    },
  ]
}]

function add_keys_obj(obj) {
  obj.keys = [obj.title];
  obj.children.forEach(function(child) {
    add_keys_obj(child)
    obj.keys.push(...child.keys)
  })
}

function add_keys(arr) {
  arr.forEach(function(obj, key) {
    add_keys_obj(obj);
  })
  return arr;
}


add_keys(nestArray)
document.querySelector("pre").innerText = JSON.stringify(nestArray, null, 2);
<pre></pre>

  • Related