在 2D JavaScript 数组周围添加填充

问题描述 投票:0回答:4

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

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 行添加了额外的零。有谁知道为什么会这样?

javascript arrays multidimensional-array
4个回答
2
投票

第一次在same数组

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

避免通过复制来添加 same 数组。

改变:

arr.push(a)

至:

arr.push([...a])

1
投票

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


1
投票

@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
投票

我发现 @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];
};
© www.soinside.com 2019 - 2024. All rights reserved.