I am attempting to create a function that pads a 2D array with zeros. I have made the following function:
function addPadding(arr){
var a = new Array(arr.length 2).fill(0)
//left and right padding
arr.forEach(el => {
el.push(0)
el.unshift(0)
})
//top padding
arr.unshift(a)
//bottom padding
arr.push(a)
return arr;
}
console.table(addPadding(addPadding([[1,2],[3,4]])));
The function works fine if I only call it once, but if I call it twice, like in this example, I get the following table:
My function has an unintended result, it has added extra zeroes for 2 rows. Does anyone know why this is happening?
CodePudding user response:
The first time you are padding at top and bottom the same array a
. This means the second time that same array gets padded (left & right) twice.
Avoid adding the same array by taking a copy.
Change:
arr.push(a)
to:
arr.push([...a])
CodePudding user response:
Good answer from @trincot, I just wanted to propose this syntax:
function addPadding(arr) {
const a = new Array(arr.length 2).fill(0)
return [a, ...arr.map(el => [0, ...el, 0]), a]
}
console.log(addPadding(addPadding([[1,2],[3,4]])))
CodePudding user response:
In order for your function to be idempotent, you need to check if your array has already been padded. You could do this by checking to see if all the "outer edges" are 0. You could think of this a a "frame":
const getFrame = (arr) => {
const topEdge = arr[0];
const bottomEdge = arr[arr.length-1];
const leftEdge = arr.map(row => row[0]);
const rightEdge = arr.map(row => row[row.length-1]);
return [topEdge, bottomEdge, leftEdge, rightEdge];
};
Now we simply walk the frame to see if all the values are zero:
const isAllZeros = (frame) => {
return frame.every(edge => {
return edge.every(n => {
return (n === 0);
});
});
};
Now we know when to pad or not to pad. So we write the function that pads:
const padArray = (arr) => {
let newArray = [];
let firstAndLastRow = new Array(arr[0].length 2).fill(0);
newArray.push(firstAndLastRow);
arr.forEach(oldRow => {
let newRow = Array.from(oldRow);
newRow.unshift(0);
newRow.push(0);
newArray.push(newRow);
});
newArray.push(firstAndLastRow);
return newArray;
};
const getFrame = (arr) => {
const topEdge = arr[0];
const bottomEdge = arr[arr.length-1];
const leftEdge = arr.map(row => row[0]);
const rightEdge = arr.map(row => row[row.length-1]);
return [topEdge, bottomEdge, leftEdge, rightEdge];
};
const isAllZeros = (frame) => {
return frame.every(edge => {
return edge.every(n => {
return (n == 0);
});
});
};
const padArray = (arr) => {
let newArray = [];
let firstAndLastRow = new Array(arr[0].length 2).fill(0);
newArray.push(firstAndLastRow);
arr.forEach(oldRow => {
let newRow = Array.from(oldRow);
newRow.unshift(0);
newRow.push(0);
newArray.push(newRow);
});
newArray.push(firstAndLastRow);
return newArray;
};
// debugging stuff
const rowsEl = document.getElementById('rows');
const colsEl = document.getElementById('cols');
const generateButton = document.getElementById('gen');
const padButton = document.getElementById('pad');
const vis = document.getElementById('vis');
const dbg = document.getElementById('dbg');
let arr2d = [];
generateButton.addEventListener('click', () => {
const rows = rowsEl.valueAsNumber;
const cols = colsEl.valueAsNumber;
arr2d = [];
for (let row=0; row<rows; row ) {
let thisRow = [];
for (let col=0; col<cols; col ) {
thisRow.push(Math.floor(Math.random()*10));
}
arr2d.push(thisRow);
}
showArray(arr2d);
});
padButton.addEventListener('click', () => {
const frame = getFrame(arr2d);
const isPadded = isAllZeros(frame);
if (!isPadded) {
arr2d = padArray(arr2d);
}
showArray(arr2d);
});
const showArray = (arr) => {
let txt = '';
arr.forEach(row => {
txt = "\n" `${row.join(" ")}`;
});
vis.innerText = txt;
const frame = getFrame(arr2d);
const isPadded = isAllZeros(frame);
};
<form name=f id=f>
<table>
<tr>
<td><label for=rows>rows</label></td>
<td><input type=number name=rows id=rows value=3 /></td>
</tr>
<tr>
<td><label for=cols>cols</label></td>
<td><input type=number name=cols id=cols value=3 /></td>
</tr>
<tr>
<td><button id=gen type=button>generate</button></td>
<td><button id=pad type=button>pad</button></td>
</tr>
</table>
</form>
<pre id="vis"></pre>