2

I have an array of objects that can have other arrays of object as children (it can have a complex hierarchy): if an object has a children prop — it's a group, if it doesn't — it's an item:

var myData = [
  {
      "name": "item 1"
  },
  {
      "name": "group 1",
      "children": [
      {
          "name": "item in a group 1"
      }]
  },
  {
      "name": "group 2",
      "children": [
      {
          "name": "group 1 in a group 2",
          "children": [
          {
              "name": "item in a nested group 1"
          },
          {
              "name": "deeply nested group",
              "children": [
              {
                  "name": "deep item"
              }]
          },]
      },
      {
          "name": "group 2 in a group 2",
          "children": [
          {
              "name": "item in a nested group 2"
          }]
      }]
  }]

and I want to parse it to have a flat object that would have all groups as props and items as arrays, each prop would also include items from grandchildren groups.

Currently with the code below I'm able to flatten the array and have groups as props and items as arrays for each object:

{
    "root": [
        "item 1"
    ],
    "group 1": [
        "item in a group 1"
    ],
    "group 2": [],
    "group 1 in a group 2": [
        "item in a nested group 1"
    ],
    "deeply nested group": [
        "deep item"
    ],
    "group 2 in a group 2": [
        "item in a nested group 2"
    ]
}

However I 'm struggling with adding grandchildren. Here's the desired output:

{
    "root": [
        "item 1"
    ],
    "group 1": [
        "item in a group 1"
    ],
    "group 2": [
        "item in a nested group 1", // includes items of child groups
        "item in a nested group 2",
        "deep item"
    ],
    "group 1 in a group 2": [
        "item in a nested group 1",
        "deep item" // includes item of a child group
    ],
    "deeply nested group": [
        "deep item"
    ],
    "group 2 in a group 2": [
        "item in a nested group 2"
    ]
}

here's my code I'm using (I can only use older version of pure JS so no ES6, NPM; can use polyfill though)

var myItems = {
    'root': []
}
var i;

for (i = 0; i < myData.length; i++)
{
    parseItems(myData[i], 'root')
}

function parseItems(data, groupName)
{
    var key, i;
    for (key in data)
    {
        if (!data.hasOwnProperty(key))
          continue;
        else if (data.hasOwnProperty('children'))
        {
            groupName = data['name']
            if (myItems[groupName] == undefined) myItems[groupName] = []
            for (i = 0; i < data[key].length; i++)
            {
                parseItems(data[key][i], groupName);
            }
        }
        else
        {
            myItems[groupName].push(data['name']);
        }
    }
}

And I don't understand how can I make a version of this code (or something better probably?) that'd fill parent groups with grandchildren items.

4
  • Do your Objects have an ID? Commented Jun 15, 2020 at 6:10
  • why don't you have "group 1" in "root"? Commented Jun 15, 2020 at 6:12
  • @NinaScholz I kept root for items that are on top level of the array but aren't groups (like item 1) Commented Jun 15, 2020 at 6:47
  • ok. that is possible, but later you have to loop all properties of the object and find out which ones are located at root. if you inlcude all children of root, you get clean parent children relations. Commented Jun 15, 2020 at 6:51

1 Answer 1

2

Ancient version.

function flat(array, parents, target) {
    var i, j;

    parents = parents || [];
    target = target || { root: [] };

    for (i = 0; i < array.length; i++) {
        if (array[i].children) {
            flat(array[i].children, parents.concat(array[i].name), target);
            continue;
        }
        if (parents.length) {
            for (j = 0; j < parents.length; j++) {
                if (!target[parents[j]]) target[parents[j]] = [];
                target[parents[j]].push(array[i].name);
            }
        } else {
            target.root.push(array[i].name);
        }
    }

    return target;
}


var data = [{ name: "item 1" }, { name: "group 1", children: [{ name: "item in a group 1" }] }, { name: "group 2", children: [{ name: "group 1 in a group 2", children: [{ name: "item in a nested group 1" }, { name: "deeply nested group", children: [{ name: "deep item" }] }] }, { name: "group 2 in a group 2", children: [{ name: "item in a nested group 2" }] }] }],
    result = flat(data);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

6 Comments

Thank you for your reply, Nina! As I mentioned I unfortunately can't use modern JS features like .... Would it be possible to update your answer with something more ancient? :)
Thank you for the update and your time. However the result is different from my target : your script pushes grandchildren goup names in arrays and I'd need item names, plus I think your script works on 1 level of nesting and myData can have more nested groups. Basically topmost group would incude items of its own and all children item, nested group would include items of its own and its children items and so on. I've updated input data for more precise conditions, trying my best to ask that in a clear way
it works for deep nested data structure, because of the recursive nature. please see edit.
Here's a comparison of the current output and expected output: i.imgur.com/6cXWfkq.png
i don't understand the wanted result. it violates (my) rule, one children one parent. 'item in a nested group 2' has two parents.
|

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.