Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 value
                  	eval('registry' + keys + ' = \'' + value + '\''); 
               	}
                
            });        
        });
        
        console.log('registry final');
        console.log(registry);
        $scope.registry = registry;
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app>
  
  <div ng-controller="DemoCtrl" ng-init="init()">
    <pre>{{ registry | json }}</pre>
  </div>
    
</div>
like image 925
JasperZelf Avatar asked Dec 01 '15 13:12

JasperZelf


People also ask

How to convert nested object to array (flat array) JavaScript?

Use a combined approach with iterating over the array and over the keys for Convert the nested object to array (Flat array) JavaScript. Simple example code where array have objects with two or more sub objects.

How to convert an object to an array in JavaScript?

Also read, how to convert an Object to an Array in Javascript. 2. Using Spread Operator In this above code snippet, we have used the reduce function and along with that, we have used spread operator (…) which will basically spread the previous object for every iteration and add new values to it.

How to convert array to object in AutoCAD?

Table of Contents 1 Object.assign () Object.assign () is the first method we'll cover for converting an array to an object. ... 2 Loop Over Array & Construct a New Object For the second method, we're going to loop over each item in an array and add each of its values as ... 3 Reduce ()

How do you loop through an array and add values?

Loop Over Array & Construct a New Object For the second method, we're going to loop over each item in an array and add each of its values as a new property in a new object. To match the object returned in the last section, the key value will be the array index for each item.


2 Answers

Here's a solution that fits your need. Also, please, never use eval. There's always a better way in JavaScript.

You can adapt the code below to your use case.

var 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" ]
];

var o = {};

data.forEach(function(a) {
  var keys = a.slice(0, a.length-2);
  var cur = o;

  keys.forEach(function(k) {
    if (cur[k] == null) {
      cur[k] = {};
    }
    cur = cur[k];
  });

  cur[a[a.length-2]] = a[a.length-1]
});

output.innerHTML = JSON.stringify(o, null, 2);
<pre id='output'></pre>
like image 106
Brendan Molloy Avatar answered Oct 05 '22 22:10

Brendan Molloy


A compact solution which avoids the calculation of the value position in the array.

var array = [
        ["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"]
    ],
    obj = {};

array.forEach(function (a) {
    var p = obj,
        v = a.pop(),
        k = a.reduce(function (r, b) {
            p[r] = p[r] || {};
            p = p[r];
            return b;
        });
    p[k] = v;
});

document.write('<pre>' + JSON.stringify(obj, 0, 4) + '</pre>');
like image 42
Nina Scholz Avatar answered Oct 05 '22 22:10

Nina Scholz