2

I would like to dynamically write data (in the form of an object) as a value to an object nested inside another object; and to also create the name of the keys on the fly (inside a loop).

My current code looks like this:

data = {'x': 2, 'y': 3}

master_obj = {'useless': {}, 'important': {}}

var block_ind = 0
let trials = 12
let trials_per_block = 4
for (trial_ind=0; trial_ind<trials; trial_ind++) {
    // every 4 trials are in a new block
    block_ind = trial_ind % trials_per_block == 0 ? trial_ind/trials_per_block : block_ind
    
    master_obj['important']['block_0'+block_ind] = {}
    master_obj['important']['block_0'+block_ind]['trial_0'+trial_ind] = data
}
console.log(master_obj)

The output of the code looks like this (run snippet above too): Output of above snippet

Whereas the expected output is [multiple trials within a block, not a single one]:

useless: {}
important:
    block_00:
        trial_00: {x: 2, y:3}
        trial_01: {x: 2, y:3}
        trial_02: {x: 2, y:3}
        trial_03: {x: 2, y:3}
    block_01:
        trial_04: {x: 2, y:3}
        trial_05: {x: 2, y:3}
        trial_06: {x: 2, y:3}
        trial_07: {x: 2, y:3}
    block_02:
        trial_08: {x: 2, y:3}
        trial_09: {x: 2, y:3}
        trial_10: {x: 2, y:3}
        trial_11: {x: 2, y:3}

Any and all help and advice is appreciated!

npetrov937
  • 158
  • 7

1 Answers1

2

The problem is that you're not copying data, you're just reusing the same object. Another issue is that you're overwriting the object you created previously when you're trying to add another instance to an existing block.

How you copy it is a potentially-complex topic (see this question's answers), but for a shallow copy of just its own, enumerable properties, you can use either spread notation or Object.assign with an object literal, see the *** line below:

const data = {"x": 2, "y": 3}

const master_obj = {"useless": {}, "important": {}}

var block_ind = 0
let trials = 12
let trials_per_block = 4
const important = master_obj.important; // *** No need to repeat this
for (let trial_ind=0; trial_ind<trials; trial_ind++) {
//   ^^^−−−− *** Declare your variables
    // every 4 trials are in a new block
    block_ind = trial_ind % trials_per_block == 0 ? trial_ind/trials_per_block : block_ind

    // *** Only create this if it doesn't exist
    if (!important["block_0"+block_ind]) {
        important["block_0"+block_ind] = {}
    }
    important["block_0"+block_ind]["trial_0"+trial_ind] = {...data} // ***
}
console.log(master_obj)

Also note that I added const on data and master_obj. Without let, const, or var, your code was falling prey to what I call The Horror of Implicit Globals. Be sure to declare your variables. (I recommend always using const or let, never var.)


For what it's worth, you can use Math.floor(trial_ind / trials_per_block) to determine the block number. Here's that plus a couple of template literals and other constants with descriptive names:

const data = {"x": 2, "y": 3};

const master_obj = {"useless": {}, "important": {}};

const trials = 12;
const trials_per_block = 4;
const important = master_obj.important;
for (let trial_ind = 0; trial_ind < trials; ++trial_ind) {
    // Every 4 trials are in a new block
    const blockKey = `block_0${Math.floor(trial_ind / trials_per_block)}`;

    const trialKey = `trial_0${trial_ind}`;

    if (!important[blockKey]) {
        important[blockKey] = {};
    }
    important[blockKey][trialKey] = {...data};
}
console.log(master_obj);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks for your input @T.J. Crowder! I thought it would be something to do with how JavaScript handles references but I don't fully get it. Unfortunately, copying the contents of `data` as you suggest still does not get me to my desired output as I would like to create more key-value pairs within each block (not just a single trial nested within a single block). – npetrov937 Mar 10 '21 at 12:17
  • @npetrov937 - I realized that as I was suggesting a more concise version. I've updated the answer, I think it produces what you're looking for now. – T.J. Crowder Mar 10 '21 at 12:20
  • Amazing! Thanks! So I was creating the block every single loop and just creating a new trial object inside it so it was getting overwritten. Thanks a lot for your helpful suggestions; they are greatly appreciated! – npetrov937 Mar 10 '21 at 12:23
  • 1
    @npetrov937 - My pleasure. FWIW, I added a bit more to the end of the answer. Happy coding! – T.J. Crowder Mar 10 '21 at 12:24