我正在尝试创建一个用零填充二维数组的函数。我做了以下功能:
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]])));
如果我只调用它一次,该函数就可以正常工作,但是如果我调用它两次,就像在这个例子中一样,我会得到下表:
我的函数出现了意外结果,它为 2 行添加了额外的零。有谁知道为什么会这样?
第一次在same数组
a
的顶部和底部填充。这意味着同一个数组第二次被填充(左和右)两次。
避免通过复制来添加 same 数组。
改变:
arr.push(a)
至:
arr.push([...a])
为了使您的函数具有幂等性,您需要检查您的数组是否已被填充。您可以通过检查所有“外边缘”是否都为 0 来做到这一点。您可以将其视为一个“框架”:
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;
};
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>
@trincot 的回答很好,我只是想提出这个语法:
function addPadding(arr) {
const a = new Array(arr.length + 2).fill(0)
return [a, ...arr.map(el => [0, ...el, 0]), a]
}
const arr = addPadding(addPadding([[1,2],[3,4]]))
arr.forEach(el => document.write(el + '<br>'))
我发现 @Jean Will 的语法对我的情况很有用 (链接),但我对 TypeScript 和泛型进行了一些调整。由于数组类型是动态的,填充值现在也是一个参数。
还修复了非方形数组的错误:
arr.length + 2
应该是arr[0].length + 2
。
const padArray = <T>(arr: T[][], fill: T) => {
const a = new Array<T>(arr[0].length + 2).fill(fill);
return [a, ...arr.map((x) => [fill, ...x, fill]), a];
};