如何使用类似映射的函数创建数组的浅表副本?
How can I create a shallow copy of an array with a map like function?
如果我有一个 4x4 二维数组并想处理特定列,我可以使用映射获取它并将其设置回去,或者我可以获得它的浅表副本并直接处理原始数组值.
get/set方式
// create the original array
let arr = [...Array(4)].map(e => Array(4).fill(0))
console.log(arr)
// get a specific column, e.g. the 3d
let myColumn = arr.map(tile => tile[3])
// change it
myColumn[2] = 1
// set it back
arr.map((line, i) => line[3] = myColumn[i])
console.log("modified array", arr)
现在,我怎样才能用浅拷贝实现同样的事情,即不必重新设置值?
更新
这是我的(丑陋的)getter/setter 功能,可能非常完美。它甚至没有在每种情况下正确地进行深度复制(例如 index > 11
的获取),但它仍然可以完成工作。
const getLine = (index) => {
if (index < 4) return field.map(fieldLine => fieldLine[index])
if (index > 3 && index < 8) return field[index - 4].slice().reverse()
if (index > 7 && index < 12) return field.map(fieldLine => fieldLine[Math.abs(index - 11)]).slice().reverse()
if (index > 11) return field.slice()[Math.abs(index - 15)]
}
const setLine = (index, line) => {
if (index < 4) field.map((fieldLine, i) => fieldLine[index] = line[i])
if (index > 3 && index < 8) field[index - 4] = line.reverse()
if (index > 7 && index < 12) field.slice().reverse().map((fieldLine, i) => fieldLine[Math.abs(index - 11)] = line[i])
if (index > 11) field[Math.abs(index - 15)] = line
}
仅供参考,原来的问题在这里:https://www.codewars.com/kata/4-by-4-skyscrapers
如果你想制作一个浅拷贝,你必须使用一个对象,而不是一个基元。
代码可能如下所示:
// filling the array:
/*...*/.fill({value: 0})
// changing the value:
myColumn[2].value = 1
我不知道你的应用程序如何resource-sensitive,但这样你的内存消耗会增加一定程度(取决于应用程序)。
// create the original array
let arr = [...Array(4)].map(e => Array(4).fill(0))
console.log(arr)
// get copy of arr with changed column
const cloneSquareAndChangeColumn = (square, colIndex, newValue) => {
return square.map((row, col) => {
return [...row.slice(0, colIndex), newValue, ...row.slice(colIndex + 1)];
});
}
// test changing last column
console.log("cloned and changed arr: \n", cloneSquareAndChangeColumn(arr, 3, 1));
您 cannot make a "shallow copy" of primitive values - 当您制作 arr.map(tile => tile[3])
时,您正在制作一个具有 新 值的新数组,因此更改一个不会更改另一个。
但是,您可以创建一个包含 个对象的数组,因为对象的值是它们的引用
let grid = [
[{value: 1}, {value: 2}],
[{value: 3}, {value: 4}],
];
//take a column
let col2 = grid.map(row => row[1]);
//change one value
col2[1].value = 42;
//the original changed
console.log(grid);
如果您需要根据列进行频繁更改,则无需每次都执行 map(row => row[columnNumber])
甚至 matrix transposition 即可有效地旋转网格。您可以简单地制作 两个 网格 - 一个代表列,其他代表行。如果您首先从 "normal" 网格开始,用对象填充它然后转置它,那么您将有效地对同一数据有两个视图:
let rows = [
[ {cell: "a1"}, {cell: "a2"}, {cell: "a3"}, {cell: "a4"} ],
[ {cell: "b1"}, {cell: "b2"}, {cell: "b3"}, {cell: "b4"} ],
[ {cell: "c1"}, {cell: "c2"}, {cell: "c3"}, {cell: "c4"} ],
[ {cell: "d1"}, {cell: "d2"}, {cell: "d3"}, {cell: "d4"} ]
];
//transpose
let columns = rows[0].map((col, i) => rows.map(row => row[i]));
//show
console.log("rows:");
console.log(format(rows));
console.log("----");
console.log("columns:");
console.log(format(columns));
console.log("----");
//take a column
let col2 = columns[1];
//update a value
col2[2].cell = "XX";
//show again
console.log("after the change");
console.log("rows:");
console.log(format(rows));
console.log("----");
console.log("columns:");
console.log(format(columns));
console.log("----");
//helper function to display the grids more compactly
function format(arr) {
return arr
.map(arr => arr.map(({cell}) => cell).join())
.join("\n");
}
如果我有一个 4x4 二维数组并想处理特定列,我可以使用映射获取它并将其设置回去,或者我可以获得它的浅表副本并直接处理原始数组值.
get/set方式
// create the original array
let arr = [...Array(4)].map(e => Array(4).fill(0))
console.log(arr)
// get a specific column, e.g. the 3d
let myColumn = arr.map(tile => tile[3])
// change it
myColumn[2] = 1
// set it back
arr.map((line, i) => line[3] = myColumn[i])
console.log("modified array", arr)
更新
这是我的(丑陋的)getter/setter 功能,可能非常完美。它甚至没有在每种情况下正确地进行深度复制(例如 index > 11
的获取),但它仍然可以完成工作。
const getLine = (index) => {
if (index < 4) return field.map(fieldLine => fieldLine[index])
if (index > 3 && index < 8) return field[index - 4].slice().reverse()
if (index > 7 && index < 12) return field.map(fieldLine => fieldLine[Math.abs(index - 11)]).slice().reverse()
if (index > 11) return field.slice()[Math.abs(index - 15)]
}
const setLine = (index, line) => {
if (index < 4) field.map((fieldLine, i) => fieldLine[index] = line[i])
if (index > 3 && index < 8) field[index - 4] = line.reverse()
if (index > 7 && index < 12) field.slice().reverse().map((fieldLine, i) => fieldLine[Math.abs(index - 11)] = line[i])
if (index > 11) field[Math.abs(index - 15)] = line
}
仅供参考,原来的问题在这里:https://www.codewars.com/kata/4-by-4-skyscrapers
如果你想制作一个浅拷贝,你必须使用一个对象,而不是一个基元。
代码可能如下所示:
// filling the array:
/*...*/.fill({value: 0})
// changing the value:
myColumn[2].value = 1
我不知道你的应用程序如何resource-sensitive,但这样你的内存消耗会增加一定程度(取决于应用程序)。
// create the original array
let arr = [...Array(4)].map(e => Array(4).fill(0))
console.log(arr)
// get copy of arr with changed column
const cloneSquareAndChangeColumn = (square, colIndex, newValue) => {
return square.map((row, col) => {
return [...row.slice(0, colIndex), newValue, ...row.slice(colIndex + 1)];
});
}
// test changing last column
console.log("cloned and changed arr: \n", cloneSquareAndChangeColumn(arr, 3, 1));
您 cannot make a "shallow copy" of primitive values - 当您制作 arr.map(tile => tile[3])
时,您正在制作一个具有 新 值的新数组,因此更改一个不会更改另一个。
但是,您可以创建一个包含 个对象的数组,因为对象的值是它们的引用
let grid = [
[{value: 1}, {value: 2}],
[{value: 3}, {value: 4}],
];
//take a column
let col2 = grid.map(row => row[1]);
//change one value
col2[1].value = 42;
//the original changed
console.log(grid);
如果您需要根据列进行频繁更改,则无需每次都执行 map(row => row[columnNumber])
甚至 matrix transposition 即可有效地旋转网格。您可以简单地制作 两个 网格 - 一个代表列,其他代表行。如果您首先从 "normal" 网格开始,用对象填充它然后转置它,那么您将有效地对同一数据有两个视图:
let rows = [
[ {cell: "a1"}, {cell: "a2"}, {cell: "a3"}, {cell: "a4"} ],
[ {cell: "b1"}, {cell: "b2"}, {cell: "b3"}, {cell: "b4"} ],
[ {cell: "c1"}, {cell: "c2"}, {cell: "c3"}, {cell: "c4"} ],
[ {cell: "d1"}, {cell: "d2"}, {cell: "d3"}, {cell: "d4"} ]
];
//transpose
let columns = rows[0].map((col, i) => rows.map(row => row[i]));
//show
console.log("rows:");
console.log(format(rows));
console.log("----");
console.log("columns:");
console.log(format(columns));
console.log("----");
//take a column
let col2 = columns[1];
//update a value
col2[2].cell = "XX";
//show again
console.log("after the change");
console.log("rows:");
console.log(format(rows));
console.log("----");
console.log("columns:");
console.log(format(columns));
console.log("----");
//helper function to display the grids more compactly
function format(arr) {
return arr
.map(arr => arr.map(({cell}) => cell).join())
.join("\n");
}