简体   繁体   中英

Javascript - convert nested arrays into object of arrays

I have a nested array with unknown shape. Here is an example:

["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
]

The arrays all have a length of 2 or greater. An array can contain any number of other arrays which can also contain any number of arrays. All values are either strings or arrays.

I'm trying to convert this into a single object with the following shape:

{"head": ["val1","val2","val3", 
    {"head2": ["val4","val5", 
        {"head3": ["val6","val7", 
            {"head4": ["val8"]}, "val9"]},
    {"head5": ["val10", "val11"]}
]}

Basically, each array needs to be converted to an object where the first value is the key and the rest of the array is the value. I've tried using reduce but can't quite get it right.

In this case, you don't know how deep your nested arrays are, so it is a good idea to design a recursive function.

In the base case of your recursive function, the input is not an array, so just return the input.

In the case when the input is an array, create a JS object with a single property whose name is equal to the first element in the input array, and whose value is equal to the rest of the array... You need to recursively call your function against each of the remaining members to get their value in the resulting array.

 var a = ["head","val1","val2","val3", ["head2","val4","val5", ["head3","val6","val7", ["head4", "val8"],"val9"]], ["head5", "val10", "val11"] ]; function convert(val) { var result; if (Array.isArray(val)) { var key = val[0]; var vals = val.slice(1); result = {}; result[key] = []; for (var i = 0; i < vals.length; i++) { result[key].push(convert(vals[i])); } } else { result = val; } return result; } console.log(convert(a)); 

Just do it recursively like so:

function convert(arr) {
  return {
    [arr[0]]: arr.slice(1).map(item => Array.isArray(item)? convert(item): item)
  }
}

The function convert returns an object containg one key-value pair. The key is arr[0] and the value is the rest of the elements in the array ( arr.slice(1) ) mapped into a new array such that convert is called on all array elements inside that array.

ES5 Version:

 function convert(arr) { var obj = {}; obj[arr[0]] = arr.slice(1).map(function(item) { return item instanceof Array? convert(item): item; }); return obj; } 

Example:

 function convert(arr) { return { [arr[0]]: arr.slice(1).map(item => Array.isArray(item)? convert(item): item) } } let arr = ["head","val1","val2","val3", ["head2","val4","val5", ["head3","val6","val7", ["head4", "val8"],"val9"]], ["head5", "val10", "val11"] ]; let result = convert(arr); console.log(result); 

Something like this?

 function convert(arr) { if (arr instanceof Array) { const [key, ...values] = arr; return { [key]: values.map(convert) }; } else { return arr; } } const test = ["head","val1","val2","val3", ["head2","val4","val5", ["head3","val6","val7", ["head4", "val8"],"val9"]], ["head5", "val10", "val11"] ]; console.log(convert(test)); 

ES6: You can do something like the following

function convertArrayToObject(arr) {
  return Array.isArray(arr) && arr.length ? {
    [arr[0]]: arr.slice(1).map(convertArrayToObject)
  } : arr;
}

This Code defines a function convertArrayToObject which returns the element itself if it's not an array or sets the first element as the key and calls the function if with the remaining elements as the values if it's an array.

This efficient approach avoids using slice() (which would create a temporary array of size N-1 that gets dropped):

 function change(a) { let b = []; for (let i = 1; i < a.length; i++) { let v = a[i]; b.push(Array.isArray(v) ? change(v) : v); } return {[a[0]]: b}; } console.log(change( ["head","val1","val2","val3", ["head2","val4","val5", ["head3","val6","val7", ["head4", "val8"],"val9"]], ["head5", "val10", "val11"] ] )); 

Since you tagged this with lodash here is a short solution with it as well:

 var data = ["head","val1","val2","val3", ["head2","val4","val5", ["head3","val6","val7", ["head4", "val8"],"val9"]], ["head5", "val10", "val11"] ] const f = (d) => ({[_.head(d)]: _.map(_.tail(d), x => _.isArray(x) ? f(x) : x)}) console.log(f(data)) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script> 

It is a recursive solution which utilizes lodash .head to get the first element of the array, .tail to get all but the first and then _.map to go over each of the elements and return an array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM