在二维 JavaScript 数组周围添加填充

Adding padding around a 2D JavaScript array

我正在尝试创建一个用零填充二维数组的函数。我做了以下功能:

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]])));

如果我只调用它一次,该函数工作正常,但如果我调用它两次,就像在这个例子中,我得到以下 table:

我的函数有一个意外的结果,它为 2 行添加了额外的零。有谁知道为什么会这样?

第一次在 相同 数组 a 的顶部和底部填充。这意味着同一个数组第二次被填充(左和右)两次。

通过复制避免添加相同数组。

变化:

arr.push(a)

至:

arr.push([...a])

来自@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>'))

为了让你的函数是幂等的,你需要检查你的数组是否已经被填充。您可以通过检查所有“外边缘”是否为 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>