【问题标题】:Understanding Arrow functions with an Example通过示例了解箭头函数
【发布时间】:2018-04-25 20:19:03
【问题描述】:

我无法理解使用箭头函数和 .every() 方法的编码挑战的解决方案,并希望有更多知识的人可以解释发生了什么。挑战是检查网格以查看它是否代表真正的数独板。我理解第一部分连接并乘以行/列/正方形,但无法理解后半部分...

// True, if product of #s in row is 9!
p = a => eval(a.join("*")) == (1*2*3*4*5*6*7*8*9);

// Check each row, column and 3 block grid using p() 
sudoku = grid => 
  grid.every((r,i) =>
    p(r) &&
    p(grid.map(r => r[i])) &&
    p(r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) )

感谢您的帮助!

【问题讨论】:

  • 旁注:验证功能不正确。由于它只检查集合的乘积,它会在 (2, 4, 8) 分别替换为 (4, 4, 4) 的行上失败(例如)。
  • 你所说的“后半部分”是什么?您已经描述了第二条语句(sudoku 函数)的作用。

标签: javascript ecmascript-6 sudoku arrow-functions


【解决方案1】:

似乎数独的输入数据是这样的二维数组:

let grid = [
  [2,4,1,7,6,8,5,3,9],
  [5,7,3,9,2,4,1,8,6],
  [8,9,6,5,3,1,7,4,2],
  [7,3,4,2,9,5,6,1,8],
  [1,8,9,4,7,6,3,2,5],
  [6,5,2,8,1,3,4,9,7],
  [4,6,5,3,8,2,9,7,1],
  [3,2,7,1,5,9,8,6,4],
  [9,1,8,6,4,7,2,5,3]
]

要验证数独,我们必须检查所有行、列和子网格

代码说明:

p = a => eval(a.join("*")) == (1*2*3*4*5*6*7*8*9);

这是

的等价物
p = function(a) {
  return eval(a.join("*")) == (1*2*3*4*5*6*7*8*9);
}

所以函数“p”得到整数数组

[2,4,1,7,6,8,5,3,9]

用“*”连接所有整数,结果我们有:

"2*4*1*7*6*8*5*3*9"

然后评估这个字符串,结果我们有:

362880

这与1*2*3*4*5*6*7*8*9的值相同

所以现在我们可以用这个函数检查每一行、每一列和每个子网格。

sudoku = grid => 
  grid.every((r,i) =>
    validRows &&
    validColumns &&
    validSubGrids )

等同于:

sudoku = function(grid) {
  grid.every( function(r, i) {
    return 
      validRows &&
      validColumns &&
      validSubGrids
  })
}

every 方法对数组中存在的每个元素执行一次提供的回调函数,直到找到一个回调函数返回虚假值。否则返回 true。

有效的数独意味着我们的every 函数的回调为所有元素返回true

p(r) - 验证每一行

p(grid.map(r => r[i])) - 验证每一列

函数map 创建新数组。 例如。对于i=0,它将提供以下结果:

[ grid[0][0], grid[0][1], grid[0][2],...]

p(r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) ) - 验证每个子网格

等效代码:

p(
  r.map( function(_,j) {
    let row = 3 * Math.floor(i/3) + Math.floor(j/3)
    let column = 3 * (i%3) + (j%3)
    return grid[row][column]
  })
)

因此,我们验证了所有行、所有列和所有子网格。

【讨论】:

    【解决方案2】:

    在大多数情况下,箭头函数只是一个函数。两者之间唯一真正的区别是this 在使用箭头函数时从外部上下文中保留,而this 是用于使用普通函数调用函数的this

    function A() {
      this.v = 1;
      this.a = () => console.log(this.v);
      this.b = function () { console.log(this.v) };
    }
    
    // Both will use `obj` as `this`
    const obj = new A();
    obj.a();
    obj.b();
    
    // The arrow-function `a()` will keep the same `this` as above, `obj` will change.
    const obj2 = { v: 2 };
    obj2.a = obj.a;
    obj2.b = obj.b;
    obj2.a();
    obj2.b();

    另一个可能让你失望的区别是箭头函数,如果它只需要一行,你可以省略大括号({}),它会返回值。即,

    a => 1
    

    等同于:

    function (a) { return 1; }
    

    在此示例代码中,作为箭头函数或常规函数并没有什么不同,因为 this 没有被调用。

    代码的作用是:

    grid.every((r, i) =>
    

    查看grid 中的每个元素,只要它返回true,就继续前进。 rgrid 的当前值,i 是它正在处理的当前索引。

    grid.map(r => r[i])
    

    实际上只是从r 获取i-th 值并返回它。这将用于检查二维数组的对角线。 (所以它得到grid[0][0]grid[1][1] 等等)。

    r.map((_, j) => grid[math])
    

    然后只是循环遍历r 中的每个元素,并使用来自外部循环的当前i 索引和来自rj 索引获取一些元素(基于该数学)。使用_ 作为参数名称是一种常见约定,表明您只是不关心该参数。

    【讨论】:

      【解决方案3】:
      sudoku = grid => 
        grid.every((r,i) =>
          p(r) &&
          p(grid.map(r => r[i])) &&
          p(r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) )
      
      1. 对于网格中的每个项目 r,都会评估 p(r)。如果它是真的,那么第二部分将被评估
      2. grid.map(r => r[i]) 将被评估,然后将遍历所有网格项并返回其第 i 个元素的数组。

        现在,如果p(grid.map(r => r[i])) 为真,则将评估后半部分。

      3. 最后 r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) 将被执行,但前提是前两个条件为真。

        这还将返回一个网格项数组,具体取决于 i 和 j 的值。

      所以这里的重点是&&

      的用法

      A && B 将在 A 计算结果为真时返回 B(并且 B 将仅在 A 为真时计算)

      【讨论】:

        猜你喜欢
        • 2020-09-09
        • 1970-01-01
        • 1970-01-01
        • 2021-08-15
        • 2019-06-03
        • 2011-01-06
        • 2017-03-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多