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!
1 Answer 1
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);
4 Comments
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).