1

I have an array with infinite levels in each object and want to add an id field based on the level. For level 1 the ID should be 1, for level two the ID should be 2, etc.

{
    "name": "Anything2",
    "code": "SS_1",
    "levels": [
        {
            "levelName": "New level",
            "levels": [
                {
                    "levelName": "New Level2",
                    "levels": [
                        {
                            "levelName": "New Level2",
                            {
                                "levelName": "New Level2",
                                "levels": [
                                    {
                                        "levelName": "New level"
                                    }
                                ]
                            }
                        },
                        {
                            "levelName": "New Level2",
                        },
                        {
                            "levelName": "New Level2",
                        }
                    ]
                },
                {
                    "levelName": "New Level2"
                },
                {
                    "levelName": "New Level2",
                    "levels": [
                        {
                            "levelName": "New level"
                        }
                    ]
                }
            ]
        }
    ]
}

I want to convert the above array into below new array. I have tried using a for loop, but it's not working. I am not getting the expected data.

{
    "name": "Anything2",
    "code": "SS_1",
    "levels": [
        {
            "level": 1,
            "levelName": "New level",
            "levels": [
                {
                    "level": 2,
                    "levelName": "New Level2",
                    "levels": [
                        {
                            "level": 3,
                            "levelName": "New Level2",
                            {
                                "levelName": "New Level2",
                                "levels": [
                                    {
                                        "level": 4,
                                        "levelName": "New level"
                                    }
                                ]
                            }
                        },
                        {
                            "level": 3,
                            "levelName": "New Level2",
                        },
                        {
                            "level": 3,
                            "levelName": "New Level2",
                        }
                    ]
                },
                {
                    "level": 2,
                    "levelName": "New Level2"
                },
                {
                    "level": 2,
                    "levelName": "New Level2",
                    "levels": [
                        {
                            "level": 3,
                            "levelName": "New level"
                        }
                    ]
                }
            ]
        }
    ]
}
1
  • Suggestion: The term "id" indicates that these are unique values. In this context, it might make more sense to call it "level". Commented Jan 14, 2022 at 11:00

4 Answers 4

1

You could take a recursive approach and hand over an incremented level for each level.

addLevels takes a level variable and returns a nother function which separates levels from the object. The rest of the object is a new variable.

The inner function returns a new object with a level property, the old object without levels and a property levels which gets the mapping of the nested arrays.

addLevel features a closure over level which keeps the value for the nested function.

const
    addLevel = (level = 0) => ({ levels = [], ...o }) =>
        ({ level, ...o, levels: levels.map(addLevel(level + 1)) }),
    data = { name: "Anything2", code: "SS_1", levels: [{ levelName: "New level", levels: [{ levelName: "New Level2", levels: [{ levelName: "New Level2" }, { levelName: "New Level2", levels: [{ levelName: "New level" }] }, { levelName: "New Level2" }, { levelName: "New Level2" }] }, { levelName: "New Level2" }, { levelName: "New Level2", levels: [{ levelName: "New level" }] }] }] },
    result = addLevel()(data);

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

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

3 Comments

Сould you tell please how this solution works? It kind of magic!
@AlexandrBelan, please see edit.
@AlexandrBelan You can think this twisted piece of code looks magical, but according to jsbench.me it is 100% slower than my good old while loop stackoverflow.com/a/70725822/6316468.
0

Here I call the property "depth":

const data = {
  "name": "Anything2",
  "code": "SS_1",
  "levels": [{
    "levelName": "New level",
    "levels": [{
        "levelName": "New Level2",
        "levels": [{
            "levelName": "New Level2"
          },
          {
            "levelName": "New Level2",
            "levels": [{
              "levelName": "New level"
            }]
          },
          {
            "levelName": "New Level2"
          },
          {
            "levelName": "New Level2"
          }
        ]
      },
      {
        "levelName": "New Level2"
      },
      {
        "levelName": "New Level2",
        "levels": [{
          "levelName": "New level"
        }]
      }
    ]
  }]
};

function addleveldepth(arr, depth = 1) {
  arr.forEach(obj => {
    obj.depth = depth;
    if (obj.levels) {
      addleveldepth(obj.levels, depth + 1);
    }
  });
}

addleveldepth(data.levels);

console.log(data);

Comments

0

Think it works:

const data = {"name": "Anything2","code": "SS_1","levels": [{"levelName": "New level","levels": [{"levelName": "New Level2","levels": [{"levelName": "New Level2","levels": [{"levelName": "New level"}]},{"levelName": "New Level2",},{"levelName": "New Level2",}]},{"levelName": "New Level2"},{"levelName": "New Level2","levels": [{"levelName": "New level"}]}]}]};
        

const iter = (arr, level) => 
  arr.map((obj) => 
    Array.isArray(obj.levels) 
      ? { level, ...obj,  levels: iter(obj.levels, level + 1) } 
      : { level, ...obj });

const result = {...data, levels: iter(data.levels, 1) };

console.dir(result,  {depth: null})
.as-console-wrapper{min-height: 100%!important; top: 0}

1 Comment

Thanks for your help but using above user6316468 solution.
0

Here is a simple solution using a stack and a while loop.

var tree = {
  children: [{
    children: [{
      children: []
    }, {
      children: []
    }]
  }, {
    children: [{
      children: []
    }]
  }]
};

var stack = [
  [tree, 0] // `0` is the `i` below
];

var n; while (n = stack.length) {
  let [node, i] = stack[n - 1];
  if (i < node.children.length) {
    stack.push([node.children[i], 0]);
    stack[n - 1][1]++; // increment `i`
  } else {
    stack.pop();
    node.depth = n;
  }
}

console.log(tree);

1 Comment

This works fine, thanku so much.

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.