1

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: []
              }
            ]
         },
      ]
   },
   {...},
   {...}
]
6
  • 1
    what you tried ? Commented Jul 3, 2022 at 12:42
  • sorry. the things I've tried aren't really worth putting in this post. do you agree to ignore them? Commented Jul 3, 2022 at 12:53
  • 1
    you're completely right. i edited my post and you can take a glance at them Commented Jul 3, 2022 at 13:29
  • 1
    Under the title: "title 1" they keys need to include the items from both 1-1 and 1-2 --> in the above question, right? Commented Jul 3, 2022 at 13:40
  • 1
    my bad, that's right. Commented Jul 3, 2022 at 13:46

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

amazing solution. while it doesn't change or affect the original array and returns a new one. thank you so much.
Something I've learned rather recently - if we need to keep the original object or array as-is and obtain something new, one very simple way is to use structuredClone(). While the above solution creates a copy by spreading (...) at an element-level appears to work, if we simply did structuredClone(arr).map at the first-line - it will also ensure that the original arr remains unaffected.
2

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>

1 Comment

I'm improving the code, needs a little shortening so check it out later. Or try yourself even.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.