Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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()?

like image 922
Aaron von Schassen Avatar asked Nov 25 '19 09:11

Aaron von Schassen


1 Answers

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; }
like image 85
Nina Scholz Avatar answered Sep 25 '22 13:09

Nina Scholz