需要帮助理解Javascript中的这个片段(转置数组)
Need help understanding this snippet (transposing an array) in Javascript
我发现这段代码可以将一个数组转置到另一个 post 上,但我不明白为什么我们只对数组的第一个元素进行操作 a[0]
。另外,下划线有什么作用? (当我 google 下划线时,我得到的只是下划线库)。
function transpose(a)
{
return a[0].map(function (_, c) { return a.map(function (r) { return r[c]; }); });
}
该代码确实转置了一个矩阵(二维数组)。
外部 map
调用对 a[0]
进行操作,以获取列索引并生成 "columns" 长的输出数组(如果输入是 mn,它 returns 一个包含 n 个条目的新数组)。未使用第一个参数,因此使用占位符标识符 (_
)。第二个参数(列索引)用于内部映射以访问正确的单元格。
在该调用中,进行了另一个 map
调用,这次是针对整个数组,它有效地映射了行。每一行(单元格数组)都变成单个值 r[c]
,这些值一起生成返回到外部映射的输出数组。
让我们扩展代码以提高可读性并浏览它:
// Pass an array to transpose: i.e. transpose(myArray);
function transpose(a){
// return the array returned from calling the .map method
// on the first item in the array (this assumes that the first
// item in the array is, itself, an array:
return a[0].map(
// Provide the function for the map to use
// This function can take 3 arguments for:
// currentValue, index, array
// The code below would access currentValue with _
// and index with c
function (_, c) {
// The mapping callback function's job is to return
// values that will be placed into a new array that
// the overall .map method creates. Here, the callback
// is calling .map on the original array:
return a.map(
// This callback is using the variable r to
// receive the currentValue of the array element
// being looped over (which is assumed to be an
// array itself here:
function(r) {
// This function returns elemeent at index
// position: c from the array element r and
// adds this to the new array being created
// by the nested .map call
return r[c];
});
});
}
现在,参数名称:_、c、r是作者简单选择的,但是对于.map()
,最好使用val
、index
和arr
(或非常相似的名称)以记住 .map()
回调函数的参数代表什么。
此函数作用于传入数组 (a
) 的第一个元素,即 a[0]
,它本身就是一个数组。
然后它遍历原始数组的元素,在与第一个数组对应的索引位置处获取元素,但从第二个数组中获取元素。
what does the underscore perform?
map()
的第一个参数被命名为 _
的原因是因为它没有被使用。
下划线是 作为未使用参数的名称。
but I don't understand why we're only acting on the first element of the array a[0]
使用a[0]
是任意的。由于矩阵中的所有行都具有相同的长度,因此任何索引都可以使用。我们这样做是为了获取列数。
本质上,第一个 map()
遍历第一行(所有列)并在每次迭代中忽略当前列值并获取当前列索引。换句话说,第一个 map()
遍历矩阵的 "width",从左到右,每次都抓取当前列索引。
第二个 map()
在第一个 map()
里面。这意味着它 对于每个列索引 迭代所有行(矩阵的高度)并且在每次迭代中,使用相应的列索引从当前行创建一个新行。
- 需要注意的重要一点是,
map
每次都会创建一个新数组,因此您正在创建一个新的转置矩阵,而不是以任何方式更改初始矩阵。
视觉示例
如果从矩阵开始:
[ ['a1', 'a2', 'a3'] ]
[ ['b1', 'b2', 'b3'] ]
然后在每一步中发生的情况(对原始矩阵使用 M
,对转置矩阵使用 T
):
// Step1
columnIndex = 0
T[columnIndex][0] becomes M[0][columnIndex] which is "a1"
T[columnIndex][1] becomes M[1][columnIndex] which is "b1"
transposed row 0 becomes ["a1", "b1"]
// Step2
columnIndex = 1
T[columnIndex][0] becomes M[0][columnIndex] which is "a2"
T[columnIndex][1] becomes M[1][columnIndex] which is "b2"
transposed row 1 becomes ["a2", "b2"]
// Step3
columnIndex = 2
T[columnIndex][0] becomes M[0][columnIndex] which is "a3"
T[columnIndex][1] becomes M[1][columnIndex] which is "b3"
transposed row 2 becomes ["a3", "b3"]
最后得到一个转置矩阵:
[ ['a1', 'b1'] ]
[ ['a2', 'b2'] ]
[ ['a3', 'b3'] ]
以下代码更改了格式和变量名,以更清楚地显示正在发生的事情。打开控制台查看每一步发生了什么。
var matrix = [];
matrix.push(['a1', 'a2', 'a3']); // first row
matrix.push(['b1', 'b2', 'b3']);
/*
matrix =
[ ['a1', 'a2', 'a3'] ]
[ ['b1', 'b2', 'b3'] ]
*/
function transpose(matrix) {
var firstRow = matrix[0];
var transposedMatrix = firstRow.map(function(UNUSED, columnIndex) {
console.debug('\ncolumnIndex = %d', columnIndex);
var transposedRow = matrix.map(function(row, idx) { // <-- idx is only used for logging, it's not necessary
console.debug('T[%d][%d] = becomes %o', columnIndex, idx, row[columnIndex]);
return row[columnIndex];
});
console.debug('transposed row %d becomes %o: ', columnIndex, transposedRow);
return transposedRow;
});
return transposedMatrix;
}
var transposed = transpose(matrix);
/*
transposed =
[ ['a1', 'b1'] ]
[ ['a2', 'b2'] ]
[ ['a3', 'b3'] ]
*/
console.dir(transposed);
我发现这段代码可以将一个数组转置到另一个 post 上,但我不明白为什么我们只对数组的第一个元素进行操作 a[0]
。另外,下划线有什么作用? (当我 google 下划线时,我得到的只是下划线库)。
function transpose(a)
{
return a[0].map(function (_, c) { return a.map(function (r) { return r[c]; }); });
}
该代码确实转置了一个矩阵(二维数组)。
外部 map
调用对 a[0]
进行操作,以获取列索引并生成 "columns" 长的输出数组(如果输入是 mn,它 returns 一个包含 n 个条目的新数组)。未使用第一个参数,因此使用占位符标识符 (_
)。第二个参数(列索引)用于内部映射以访问正确的单元格。
在该调用中,进行了另一个 map
调用,这次是针对整个数组,它有效地映射了行。每一行(单元格数组)都变成单个值 r[c]
,这些值一起生成返回到外部映射的输出数组。
让我们扩展代码以提高可读性并浏览它:
// Pass an array to transpose: i.e. transpose(myArray);
function transpose(a){
// return the array returned from calling the .map method
// on the first item in the array (this assumes that the first
// item in the array is, itself, an array:
return a[0].map(
// Provide the function for the map to use
// This function can take 3 arguments for:
// currentValue, index, array
// The code below would access currentValue with _
// and index with c
function (_, c) {
// The mapping callback function's job is to return
// values that will be placed into a new array that
// the overall .map method creates. Here, the callback
// is calling .map on the original array:
return a.map(
// This callback is using the variable r to
// receive the currentValue of the array element
// being looped over (which is assumed to be an
// array itself here:
function(r) {
// This function returns elemeent at index
// position: c from the array element r and
// adds this to the new array being created
// by the nested .map call
return r[c];
});
});
}
现在,参数名称:_、c、r是作者简单选择的,但是对于.map()
,最好使用val
、index
和arr
(或非常相似的名称)以记住 .map()
回调函数的参数代表什么。
此函数作用于传入数组 (a
) 的第一个元素,即 a[0]
,它本身就是一个数组。
然后它遍历原始数组的元素,在与第一个数组对应的索引位置处获取元素,但从第二个数组中获取元素。
what does the underscore perform?
map()
的第一个参数被命名为 _
的原因是因为它没有被使用。
下划线是
but I don't understand why we're only acting on the first element of the array a[0]
使用a[0]
是任意的。由于矩阵中的所有行都具有相同的长度,因此任何索引都可以使用。我们这样做是为了获取列数。
本质上,第一个 map()
遍历第一行(所有列)并在每次迭代中忽略当前列值并获取当前列索引。换句话说,第一个 map()
遍历矩阵的 "width",从左到右,每次都抓取当前列索引。
第二个 map()
在第一个 map()
里面。这意味着它 对于每个列索引 迭代所有行(矩阵的高度)并且在每次迭代中,使用相应的列索引从当前行创建一个新行。
- 需要注意的重要一点是,
map
每次都会创建一个新数组,因此您正在创建一个新的转置矩阵,而不是以任何方式更改初始矩阵。
视觉示例
如果从矩阵开始:
[ ['a1', 'a2', 'a3'] ]
[ ['b1', 'b2', 'b3'] ]
然后在每一步中发生的情况(对原始矩阵使用 M
,对转置矩阵使用 T
):
// Step1
columnIndex = 0
T[columnIndex][0] becomes M[0][columnIndex] which is "a1"
T[columnIndex][1] becomes M[1][columnIndex] which is "b1"
transposed row 0 becomes ["a1", "b1"]
// Step2
columnIndex = 1
T[columnIndex][0] becomes M[0][columnIndex] which is "a2"
T[columnIndex][1] becomes M[1][columnIndex] which is "b2"
transposed row 1 becomes ["a2", "b2"]
// Step3
columnIndex = 2
T[columnIndex][0] becomes M[0][columnIndex] which is "a3"
T[columnIndex][1] becomes M[1][columnIndex] which is "b3"
transposed row 2 becomes ["a3", "b3"]
最后得到一个转置矩阵:
[ ['a1', 'b1'] ]
[ ['a2', 'b2'] ]
[ ['a3', 'b3'] ]
以下代码更改了格式和变量名,以更清楚地显示正在发生的事情。打开控制台查看每一步发生了什么。
var matrix = [];
matrix.push(['a1', 'a2', 'a3']); // first row
matrix.push(['b1', 'b2', 'b3']);
/*
matrix =
[ ['a1', 'a2', 'a3'] ]
[ ['b1', 'b2', 'b3'] ]
*/
function transpose(matrix) {
var firstRow = matrix[0];
var transposedMatrix = firstRow.map(function(UNUSED, columnIndex) {
console.debug('\ncolumnIndex = %d', columnIndex);
var transposedRow = matrix.map(function(row, idx) { // <-- idx is only used for logging, it's not necessary
console.debug('T[%d][%d] = becomes %o', columnIndex, idx, row[columnIndex]);
return row[columnIndex];
});
console.debug('transposed row %d becomes %o: ', columnIndex, transposedRow);
return transposedRow;
});
return transposedMatrix;
}
var transposed = transpose(matrix);
/*
transposed =
[ ['a1', 'b1'] ]
[ ['a2', 'b2'] ]
[ ['a3', 'b3'] ]
*/
console.dir(transposed);