javascript - Convert nested array into object

问题描述:

An API I'm talking to returns it's registry in a very odd nested array structure. I want to convert this monstrosity into an object so my application has easy access to whole objects stored within this output.

The output the API gives me looks like this:

[

[ "settings", "autoLogout", "false" ],

[ "settings", "autoLogoutMinutes", "60" ],

[ "settings", "presets", "true" ],

[ "controller", "rs232", "ip", "192.168.1.11" ],

[ "controller", "rs232", "name", "NX-22" ],

[ "source", "M23836", "slot1", "ip", "192.168.1.30" ]

]

The last value in each array represents the value of an entry, everything before that last one adds up to the key used to save the value. Because of size limitations I can't just drop big json-encoded objects in there, so thats not a viable workaround.

I've now made a pretty dirty and slow solution involving 2 eval()'s. (I know... that's a no-no so I'm looking for a better solution) I'm guessing this can be done loads faster, but I can't figure out how...

The snippet below uses angular because my application is Angular based, but I'm open to any fast/clean solution. A vanilla js approach or some clever use of something like lodash or underscore would be very welcome.

My dirty and slow solution now

function DemoCtrl($scope){$scope.data = [

[ "settings", "autoLogout", "false" ],

[ "settings", "autoLogoutMinutes", "60" ],

[ "settings", "presets", "true" ],

[ "controller", "rs232", "ip", "192.168.1.11" ],

[ "controller", "rs232", "name", "NX-22" ],

[ "source", "M23836", "slot1", "ip", "192.168.1.30" ]

]

$scope.init = function(){

var registry = {};

angular.forEach($scope.data, function(entry){

var keys = '';

entry.forEach(function(value, key, entry){

if( key != entry.length - 1 ){

//not last of array, so must be a key

keys += '[\'' + value + '\']';

// check if the object already exists

if( !angular.isDefined( eval('registry' + keys) ) ){

eval('registry' + keys + ' = {}');

}

}else{//last one in this entry, must be the valueeval('registry' + keys + ' = \'' + value + '\'');}

Basically you just have loop over them and create nested objects. You don't need to use eval for this. There are a lot of reasons why you shouldn't use it. Performance, security, debuggability (https://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/)

Here is another option based on @Jared Smith's solution above. In his solution the keys were concatenated into string keys in a shallow map. This creates the nested object structure of my other solution.

If you're new to array.reduce(), see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce