我正在为我的JS课程做一些培训任务,但我得到了一个必须执行一个函数,该函数必须采用正整数(n)并返回类似下面的矩阵(已传递5):
[ [ 1, 0, 0, 0, 0 ],
[ 0, 1, 0, 0, 0 ],
[ 0, 0, 1, 0, 0 ],
[ 0, 0, 0, 1, 0 ],
[ 0, 0, 0, 0, 1 ] ]
我能够使用以下代码实现该功能:
function getIdentityMatrix(n) {
const mat = new Array(n).fill([]);
return mat.map((row, index) => {
row = new Array(n).fill(0);
row[index] = 1;
return row;
});
}
但是在这样做的时候,我发现了一个奇怪的行为,我无法解释...如果我稍微修改一下代码:
function getIdentityMatrix(n) {
const mat = new Array(n).fill(new Array(n).fill(0));
return mat.map((row, index) => {
row[index] = 1;
return row;
});
}
它返回这样的矩阵:
[ [ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ],
[ 1, 1, 1, 1, 1 ] ]
为什么会这样工作?就像forEach函数遍历嵌套在每行中的所有元素(它不应该这样做)一样。
谢谢您的任何建议!
答案 0 :(得分:3)
这是因为Array是引用类型。
new Array(n).fill(new Array(n).fill(0))
首先,内部new Array(n).fill(0)
将数组大小n填充为0
;接下来,外部Array(n).fill
创建一个数组,其中填充了对该内部数组的n个引用。
它不会创建n个内部数组,而仅创建对同一数组的n个引用。因此,当您更改内部数组的元素时,外部数组中的所有引用都将反映更改,因为它们都指向同一对象。
答案 1 :(得分:0)
有问题的代码与此等效:
let n = 5
let innerArr = new Array(n).fill(0)
function getIdentityMatrix(n) {
const mat = new Array(n).fill(innerArr);
return mat.map((row, index) => {
row[index] = 1;
return row;
});
}
console.log(getIdentityMatrix(n))
因为您使用的是fill
,所以基本上是在mat
数组中引用了innerArr
(which you can see clearly from the above console output)
。
然后对每个i进行row[index] = 1
,这将更改同一数组的相同值(在i索引处)。
现在您的工作示例...可以用以下简短形式编写:
const getIdentityMatrix = (n) =>
[...Array(n)].map((row, index) => {
row = Array(n).fill(0)
row[index] = 1
return row
})
console.log(getIdentityMatrix(3))
清楚地maps
覆盖了n
的新创建数组,然后spreaded
,但是然后用全新的数组引用覆盖了每个元素 。
由于该引用是全新的,因此当我们从地图上row[index] = 1
进行修改时,使用return the x
对其进行修改会产生预期的行为。
另一种实现这一目标的方法是通过map
,Object.assign和Object.values这样:
const gm = (n) => [...Array(n)].map((x,i) =>
Object.values(Object.assign(Object.assign({}, Array(n).fill(0)), {[i]:1})))
console.log(gm(3))
答案 2 :(得分:-2)
// your example is roughly equivalent to this.
const innerArray = new Array(n).fill(0);
const mat = new Array(n).fill(innerArray);
(mat[0] === mat[1] === innerArray) === true;
只有1个嵌套数组,而不是n次数组。