【问题标题】:Need help understanding this snippet (transposing an array) in Javascript需要帮助理解 Javascript 中的这个片段(转置数组)
【发布时间】:2016-03-31 18:54:41
【问题描述】:

我在另一篇文章中找到了用于转置数组的这段代码,但我不明白为什么我们只作用于数组a[0] 的第一个元素。另外,下划线的作用是什么? (当我谷歌下划线时,我得到的只是下划线库)。

function transpose(a)
{
  return a[0].map(function (_, c) { return a.map(function (r) { return r[c]; }); });
}

【问题讨论】:

  • 第一:也许他们只需要 'a' 中位置 0 的值
  • 第二:下划线可以是变量,剩下的代码不能多说,一般是下划线库
  • 它在这种情况下是一个占位符而不使用它并在第二个位置设置一个变量

标签: javascript arrays algorithm matrix transpose


【解决方案1】:

下划线的作用是什么?

map() 的第一个参数被命名为_ 的原因是它没有被使用。 下划线是 usually picked by convention 作为未使用参数的名称。

但我不明白为什么我们只作用于数组 a[0] 的第一个元素

使用a[0] 是任意的。由于矩阵中的所有行都具有相同的长度,因此任何索引都可以使用。我们这样做是为了获取列数。

基本上,第一个map() 迭代第一行(所有列),并且在每次迭代时,忽略当前列值并获取当前列索引。换句话说,第一个map() 从左到右遍历矩阵的“宽度”,每次都抓取当前列索引。

第二个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);

【讨论】:

    【解决方案2】:

    代码确实转置了一个矩阵(二维数组)。

    外部map 调用对a[0] 进行操作,以获取列索引并生成一个“列”长的输出数组(如果输入是一个mn,它返回一个n 个条目的新数组)。未使用第一个参数,因此使用了占位符标识符 (_)。第二个参数(列索引)在内部映射中用于访问正确的单元格。

    在该调用中,又进行了一次map 调用,这次是在整个数组上,它有效地映射了行。每行(一个单元格数组)都被转换为单个值r[c],它们一起生成返回到外部地图的输出数组。

    【讨论】:

      【解决方案3】:

      让我们扩展代码以获得更好的可读性并逐步完成:

      // 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],它本身就是一个数组。

      然后它遍历原始数组的元素,抓取第一个数组对应的索引位置的元素,但第二个数组的元素。

      【讨论】:

      • 如果函数接受3个参数,为什么只提供2个,js怎么知道_和c是当前值和索引,而不是三个参数的另一种组合,例如索引和数组?
      • 在 JavaScript 中,所有参数都是可选的。如果一个函数设置为采用 3 个参数并且只传递了两个参数,则该函数使用已传递的参数,并且第三个参数的值为 undefined,因为没有为它传递任何值。与所有参数一样,您可以随意调用它们,但鉴于 .map() 的回调由 JS 运行时自动调用,它控制传递给它的参数,并且 map 将传递 3 个参数:currentValue、indexPosition、实际数组。您的代码仅捕获参数名称 _ 和 c 下的前两个。
      • 不是只提供了 2 个,而是只捕获了 2 个。 JS 运行时调用您的.map() 回调并将参数传递给它。您编写的回调可以决定它希望捕获的 3 个。在整个 JavaScript 中都是如此。
      猜你喜欢
      • 2016-04-01
      • 2022-06-15
      • 1970-01-01
      • 2019-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      相关资源
      最近更新 更多