Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Array to Object

Tags:

javascript

I have an array that looks like so:

files = [
  'Dashboard/Logs/Errors',
  'Dashboard/Logs/Other',
  'Accounts/Main',
]

I want to make it look like this:

navigation = [
  {
    "title": "Dashboard",
    "dropdown": [
      {
        "title": "Logs",
        "dropdown": [
          {
            "title": "Errors",
          },
          {
            "title": "Other",
          }
        ]
      }
    ]
  },
  {
    "title": "Accounts",
    "dropdown": [
      {
        "title": "Main",
      }
    ]
  }
]

I have the following so far:

var navigation = [];
for (var i = 0; i < files.length; i++) {
  var parts = files[i].split('/');
  navigation.push({title: parts[0]});
  for (var j = 1; j < parts.length; j++) {

  }
}

I am having difficulties figuring out a decent way to do this. What I have so far already doesn't work because it creates two objects under navigation each with title: "Dashboard". Any ideas for a clever approach? Thanks :)

like image 786
Alec Fenichel Avatar asked Feb 18 '16 22:02

Alec Fenichel


People also ask

Can you convert array to object in JavaScript?

To convert an array to an object, use the reduce() method to iterate over the array, passing it an object as the initial value. On each iteration, assign a new key-value pair to the accumulated object and return the result. Copied!

Is array same as object in JavaScript?

Arrays are a special type of objects. The typeof operator in JavaScript returns "object" for arrays. But, JavaScript arrays are best described as arrays.


2 Answers

This should produce the desired output:

var files = [
  'Dashboard/Logs/Errors',
  'Dashboard/Logs/Other',
  'Accounts/Main',
];

var navigation = [];
// Iterates through a navigation array and returns the object with matching title, if one exists.
var getNavigationObject = function(nav, title) {
  for (var i = 0; i < nav.length; i++) {
    if (nav[i].title == title) {
      return nav[i];
    }
  }
};
// Adds a file to the nav.
// The input is an array of file components (i.e. file.split('/'))
// This works by recursively adding each component of a file.
var addToNav = function (nav, components) {
  var n = getNavigationObject(nav, components[0]);
  if (!n) {
    n = {
      title: components[0]
    };
    nav.push(n);
  }
  if (components.length > 1) {
    n.dropdown = n.dropdown || [];
    addToNav(n.dropdown, components.slice(1));
  }
};

// Actually call `addToNav` on each file.
files.forEach(function(e) {
  addToNav(navigation, e.split('/'));
});

// Produces the result in string form.
JSON.stringify(navigation, null, 2)

This works by recursively checking if a given element already matches the component of the file. If it does, it recurs into that component's "dropdown". Otherwise, it creates it.

like image 190
arcyqwerty Avatar answered Nov 14 '22 22:11

arcyqwerty


This is an approach with a temporary object and some array methods with no search overhead.

var files = ['Dashboard/Logs/Errors', 'Dashboard/Logs/Other', 'Accounts/Main'],
    navigation = function (data) {
        var r = [], o = {};
        data.forEach(function (a) {
            var s = r;
            a.split('/').reduce(function (p, b) {
                if (p.children) {
                    p.value.dropdown = p.value.dropdown || [];
                    s = p.value.dropdown;
                    p = p.children;
                }
                if (!(b in p)) {
                    p[b] = { value: { title: b }, children: {} };
                    s.push(p[b].value);
                }
                return p[b];
            }, o);
        });
        return r;
    }(files);

document.write('<pre>' + JSON.stringify(navigation, 0, 4) + '</pre>');
like image 39
Nina Scholz Avatar answered Nov 14 '22 20:11

Nina Scholz