'Trying to Populate a Grid of Coordinates into a Multidimensional Array Using Nested Array Map Methods
I'm trying to populate a grid of coordinates into a multidimensional array using ES6 nested map methods using this code:
var gridSize = 4;
var regionArray = [];
for (var i = 0; i < gridSize; i++) regionArray.push(new Array(gridSize).fill({start:{x:0, y:0}, end:{x:0, y:0}}));
var regionWidth = canvas.width/gridSize;
var regionHeight = canvas.height/gridSize;
console.log(`regionWidth:${regionWidth} regionHeight:${regionHeight}`)
const hitRegions = regionArray.map((regionRow, i) => {
regionRow.forEach((region, j) => {
region.start.x = j*regionWidth;
region.end.x = j*regionWidth+regionWidth;
region.start.y = (i*regionHeight)+regionHeight;
region.end.y = (i*regionHeight)+regionHeight;
console.log(`>> region i:${i} j:${j} start.x:${region.start.x} end.x:${region.end.x} start.y:${region.start.y} end.y: ${region.end.y}`)
})
console.log('>> regionRow : ',regionRow)
return regionRow;
})
console.log(hitRegions);
The Issue I'm having is that the "regionRow" console.log is returning an array with all of the x values the same for each index.
Meanwhile the values in the ">> region" log above it is logging the correct values.
I'm trying to understand why this is happening and how to fix it..
Solution 1:[1]
In javascript everything is passed by reference, for this reason there are methods that do not directly alter the reference (Map, Filter, Reduce) in short, they return a copy of your array and it is modified on that copy.
This also happens with objects! Generally the spread operator is used to make a copy of an object and be able to modify the properties without obtaining side effects, like this:
const obj = {...oldObject}
The problem is when there are several levels in the object to mutate, Using the spread operator does not have a deep copy, therefore if we modify a property in a second level, we will be modifying the main object.
There are several options to fix this, and it will depend on how you are organizing your app:
- You can use
lodash(I think it's deprecated) with itscloneDeepmethod - You can use a library for immutability like
ImmerJS - You can create your own method to clone
To quickly solve the problem you have, I did it using JSON.parse and JSON.stringify. This way you can have a copy and modify the deep objects.
The code would look like this:
const hitRegions = regionArray.map((regionRow, i) => {
const newRegionRow = regionRow.map((region, j) => {
var newObject = JSON.parse(JSON.stringify(region))
newObject.start.x = j * regionWidth;
newObject.end.x = j * regionWidth + regionWidth;
newObject.start.y = (i * regionHeight) + regionHeight;
newObject.end.y = (i * regionHeight) + regionHeight;
return newObject
})
return newRegionRow
})
console.log(hitRegions);
This solution is a bit dangerous if your objects have functions or a value that can't be directly converted to json, so be careful.
Solution 2:[2]
The method Array.prototype.fill() copies the value to each element.
When you put an object, it just copies the reference over. Meaning that if you update one element, all elements will be changed.
You can simply use a nested for loop to get what you want:
for (let i = 0; i < gridSize; i++) {
const arr = new Array(gridSize);
for (let i = 0; i < gridSize; i++) {
arr.push({ start: { x: 1, y: 1 }, end: { x: 2, y: 2 } });
}
regionArray.push(arr);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Gianluca Fuoco |
