Aaron von Schassen
Aaron von Schassen

Reputation: 81

Multiple arrays into JavaScript object

Yes, this question has been answered a lot of times already and, trust me, I searched the internet for it. However, I haven't found a good solution after a fair amount of time.

My problem is the following:

Imagine an array of the following structure:

[
  [ 'helpers', 'ConfigHelper.java' ],
  [ 'helpers', 'GenerateRandomString.java' ],
  [ 'helpers', 'package-info.java' ],
  [ 'helpers', 'ScreenshotHelper.java' ],
  [ 'pages', 'LoginPage.java' ],
  [ 'pages', 'package-info.java' ],
  [ 'pages', 'tests', 'LoginPageTest.java' ],
  [ 'pages', 'tests', 'package-info.java' ],
  [ 'pages', 'util', 'package-info.java' ],
  [ 'pages', 'util', 'PageObject.java' ],
  [ 'pages', 'util', 'PageObjectTest.java' ],
  [ 'pages', 'util', 'PrimaryMethods.java' ],
  [ 'webDriverSetup', 'browserDriverFactories', 'ChromeDriverFactory.java'],
]

You can clearly see the duplicates of values. What I am trying to accomplish is a nested object like this:

{
  helpers: {
    "ConfigHelper.java": "",
    "GenerateRandomString.java": "",
    "package-info.java": ""
  },
  pages: {
    "LoginPage.java": "",
    "package-info.java": "",
    tests: {
      "LoginPageTest.java": "",
      "package-info.java": ""
    },
    util: {
      "package-info.java": "",
      "PageObject.java": "",
      "PageObjectTest.java": "",
      "PrimaryMethods.java": ""
    }
  },
  webDriverSetup: {
    browserDriverFactories: {
      "ChromeDriverFactory.java": ""
    }
  }
}

So each array value is basically another level of object, except the last one, which will just have a string as its value.

A promising approach would be array.reduce() like this:

let arrays = [
  [ 'helpers', 'ConfigHelper.java' ],
  [ 'helpers', 'GenerateRandomString.java' ],
  [ 'helpers', 'package-info.java' ],
  [ 'helpers', 'ScreenshotHelper.java' ],
  [ 'pages', 'LoginPage.java' ],
  [ 'pages', 'package-info.java' ],
  [ 'pages', 'tests', 'LoginPageTest.java' ],
  [ 'pages', 'tests', 'package-info.java' ],
  [ 'pages', 'util', 'package-info.java' ],
  [ 'pages', 'util', 'PageObject.java' ],
  [ 'pages', 'util', 'PageObjectTest.java' ],
  [ 'pages', 'util', 'PrimaryMethods.java' ],
  [ 'webDriverSetup', 'browserDriverFactories', 'ChromeDriverFactory.java'],
];

let treeView = {};

arrays.forEach(array => {
  array.reduce(function(o, key) {
    return o[key] = {};
  }, treeView);
});

console.log(treeView);

However, it will obviously always overwrite the values so at the end I will receive an incomplete object.

My question is:

How can I edit the function so that I receive a complete object?
or
What are alternatives to array.reduce()?

Upvotes: 7

Views: 149

Answers (2)

crani
crani

Reputation: 96

Just check if the object key already exits.

let treeView = {};

arrays.forEach(array => {
  array.reduce(function(o, key) {
    if (!treeView[key]) {
      return (o[key] = {});
    } else {
      return (o[key] = treeView[key]);
    }
  }, treeView);
});

console.log(treeView);

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386883

You could save the last value for later using this value as key for an empty string and the rest for creating a nested object.

let arrays = [['helpers', 'ConfigHelper.java'], ['helpers', 'GenerateRandomString.java'], ['helpers', 'package-info.java'], ['helpers', 'ScreenshotHelper.java'], ['pages', 'LoginPage.java'], ['pages', 'package-info.java'], ['pages', 'tests', 'LoginPageTest.java'], ['pages', 'tests', 'package-info.java'], ['pages', 'util', 'package-info.java'], ['pages', 'util', 'PageObject.java'], ['pages', 'util', 'PageObjectTest.java'], ['pages', 'util', 'PrimaryMethods.java'], ['webDriverSetup', 'browserDriverFactories', 'ChromeDriverFactory.java']],
    treeView = arrays.reduce((tree, [...array]) => {
        var last = array.pop();
        array.reduce((o, k) => o[k] = o[k] || {}, tree)[last] = '';
        return tree;
    }, {});

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

Upvotes: 11

Related Questions