11

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

9

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 [ ... ].

Sign up to request clarification or add additional context in comments.

6 Comments

Nice witchcraft... I tried to build a reduce method, but couldn't get it to work due to the accumulator moving down the tree... The reverse is a clever touch :D
@Xufox yeah, I was just reaching that conclusion myself while you were commenting - my original tests got confused by the fact that .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.
@Cerbrus actually, reduceRight() is better.
@Cerbrus I also tried it with reduce and building on a value similar to {data: [], referenceToInnerArray: []}, but Alnitak got it done sooner…
Even better :D I had no idea there was such a thing as reduceRight...
|
3

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:

  1. Construct a new element to push. This assigns a new value to current.
  2. Push the new element to the reference .push was called on.
    • That reference is the value of current before current = [].

8 Comments

question askers are fickle beasts ;-)
I'd go for an additional temporary variable to avoid the dereference in your function's second line: let next = []; current.push({[key] : next}); current = next
@Alnitak: Yea, I was a little surprised. Good suggestion :-)
Re: your edit - why abuse .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.
@Alnitak: The moment you call .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.
|
1

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.