I have the following array:
var sampleArray = [
"CONTAINER",
"BODY",
"NEWS",
"TITLE"];
I want to have the following output:
var desiredOutput = [{
"CONTAINER": [{
"BODY": [{
"NEWS": [{
"TITLE": []
}]
}]
}]
}];
How can I achieve this in JavaScript?
Already tried with recursive loop, but it does not work, gives me undefined.
dataChange(sampleArray);
function dataChange(data) {
for (var i = 0; i < data.length; i++) {
changeTheArray[data[i]] = data[i + 1];
data.splice(i, 1);
dataChange(changeTheArray[data[i]]);
}
}
Thanks
3 Answers 3
This does what you're asking for, in one line, and with no additional variables:
let desiredOutput = sampleArray.reduceRight((obj, key) => [ { [key]: obj } ], []);
The reduceRight call, starting from the right hand end of the array, progressively accumulates the current data (seeded with the initial value of []) as the value of the single key in a new object { [key] : _value_ } where that object is itself the single entry in an array [ ... ].
6 Comments
reduce method, but couldn't get it to work due to the accumulator moving down the tree... The reverse is a clever touch :D.reverse() does an in place reversal and my test data had already been corrupted. So using .reduceRight is actually better since it leaves the original array untouched.reduceRight() is better.reduce and building on a value similar to {data: [], referenceToInnerArray: []}, but Alnitak got it done sooner...reduceRight...This will do it:
const sampleArray = ["CONTAINER", "BODY", "NEWS", "TITLE"];
const data = []; // Starting element.
let current = data; // Pointer to the current element in the loop
sampleArray.forEach(key => { // For every entry, named `key` in `sampleArray`,
const next = []; // New array
current.push({[key]: next}); // Add `{key: []}` to the current array,
current = next; // Move the pointer to the array we just added.
});
console.log(data);
{[key]: next} is relatively new syntax. They're computed property names.
This:
const a = 'foo';
const b = {[a]: 'bar'};
Is similar to:
const a = 'foo';
const b = {};
b[a] = 'bar';
You could re-write the forEach as a one-liner:
const sampleArray = ["CONTAINER", "BODY", "NEWS", "TITLE"];
const data = []; // Starting element.
let current = data; // Pointer to the current element in the loop
sampleArray.forEach(key => current.push({[key]: current = [] }));
console.log(data);
This current.push works a little counter-intuitively:
- Construct a new element to push. This assigns a new value to
current. - Push the new element to the reference
.pushwas called on.- That reference is the value of
currentbeforecurrent = [].
- That reference is the value of
8 Comments
let next = []; current.push({[key] : next}); current = next.forEach with poorly understood ordering of the use of that current variable when .reduce is specifically designed to handle that accumulation? I had considered a similar solution but without reference to the language spec I couldn't be sure whether the assignment to current = [] happens before or after the .push..push. the this variable in .push is set to the old value of current. That reference doesn't change. I'm not claiming it's a good piece of code. I just realized it was possible, and wanted to add it.Hi i made a little demo :
var sampleArray = [
"CONTAINER",
"BODY",
"NEWS",
"TITLE"
],
generateArray = [],
tmp = null;
for(var i = 0; i < sampleArray.length; i++) {
if(tmp===null){
generateArray[sampleArray[i]] = {};
tmp = generateArray[sampleArray[i]];
}else{
tmp[sampleArray[i]] = {};
tmp = tmp[sampleArray[i]];
}
}
console.log(generateArray);