簡體   English   中英

如何使用類似函數的映射創建數組的淺表副本?

[英]How can I create a shallow copy of an array with a map like function?

如果我有一個 4x4 2d 數組並且想要處理特定列,我可以使用地圖獲取它並將其設置回原處,或者我可以獲得它的淺表副本並直接處理原始數組值。

獲取/設置方式

 // create the original array let arr = [...Array(4)].map(e => Array(4).fill(0)) console.log(arr) // get a specific column, eg 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 函數,可能非常完美。 它甚至在每種情況下都沒有正確地進行深度復制(例如 get with 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

不能對原始值進行“淺表復制” -當您創建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])甚至矩陣轉置來有效旋轉網格。 您可以簡單地制作兩個網格-一個代表列,另一列。 如果首先從“普通”網格開始,將其填充對象,然后對其進行轉置,那么您將有效地使用同一數據的兩個視圖:

 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"); } 

如果要進行淺表復制,則必須使用一個對象,而不是原始對象。

代碼如下:

// filling the array:
/*...*/.fill({value: 0})
// changing the value:
myColumn[2].value = 1

我不知道您的應用程序對資源的敏感程度,但是通過這種方式,您的內存消耗將在某種程度上增加(取決於應用程序)。

1.傳播算子(淺副本)

numbers = [1, 2, 3];numbersCopy = [...numbers];

注意:這不能安全地復制多維數組。 數組/對象值是按引用而不是按值復制的。

這可以

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]// numbers is left alone

這樣不好

nestedNumbers = [[1], [2]];numbersCopy = [...nestedNumbers];

2. Good Old for()循環(淺副本)

考慮到函數式編程在我們圈子中的流行程度,我認為這種方法最受歡迎。 純凈或不純凈,陳述性或命令性,就可以完成工作!

numbers = [1, 2, 3];numbersCopy = [];
for (i = 0; i < numbers.length; i++) {  
   numbersCopy[i] = numbers[i];
}

注意:這不能安全地復制多維數組。 由於使用的是=運算符,它將按引用而不是按值分配對象/數組。

這可以

numbersCopy.push(4);
console.log(numbers, numbersCopy);
// [1, 2, 3] and [1, 2, 3, 4]// numbers is left alone

這樣不好

nestedNumbers = [[1], [2]];numbersCopy = [];
for (i = 0; i < nestedNumbers.length; i++) {  
   numbersCopy[i] = nestedNumbers[i];
}
numbersCopy[0].push(300);
console.log(nestedNumbers, numbersCopy);
// [[1, 300], [2]]// [[1, 300], [2]]// They've both been changed because they share references

3. Array.map(淺副本)

要將數字列表加倍,請使用帶有double函數的map。

numbers = [1, 2, 3];
double = (x) => x * 2;
numbers.map(double);

4. Array.filter(淺拷貝)

該函數返回一個數組,就像map一樣,但是不能保證長度相同。

如果您要過濾偶數數怎么辦?

[1, 2, 3].filter((x) => x % 2 === 0)// [2]

輸入數組的長度為3,但結果長度為1。

但是,如果過濾器的謂詞始終返回true,則將獲得重復項!

numbers = [1, 2, 3];numbersCopy = numbers.filter(() => true);

每個元素均通過測試,因此將其返回。

注意:這也按引用而不是按值分配對象/數組。

5. Array.reduce(淺副本)

使用reduce克隆數組幾乎讓我感到難過,因為它的功能要強大得多。 但是,我們開始…

numbers = [1, 2, 3];
numbersCopy = numbers.reduce((newArray, element) => {  
newArray.push(element);
  return newArray;
}, []);

當它循環遍歷列表時,reduce轉換初始值。

此處的初始值是一個空數組,我們將使用每個元素填充它。 該數組必須從函數中返回,以在下一次迭代中使用。

注意:這也按引用而不是按值分配對象/數組。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM