Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何使用递归转置m*n矩阵?_Javascript_Algorithm_Recursion_Functional Programming - Fatal编程技术网

Javascript 如何使用递归转置m*n矩阵?

Javascript 如何使用递归转置m*n矩阵?,javascript,algorithm,recursion,functional-programming,Javascript,Algorithm,Recursion,Functional Programming,我试图用递归变换矩阵。现在,我知道在正常情况下,这不是一个好主意,嵌套循环/嵌套映射或类似的方法更为优越,但我需要学习这一点以达到教育目的 为了说明我做了功课,下面是嵌套循环方法: 常数矩阵=[ [3, 6, 7, 34], [6, 3, 5, 2], [2, 6, 8, 3] ]; 常数transposedMatrix=[] for(设i=0;ici>=m[0]。长度 ? [] :[m.map(r=>r[ci]),…转置(m,ci+1)] ; 常数矩阵=[ [3, 6, 7, 34], [

我试图用递归变换矩阵。现在,我知道在正常情况下,这不是一个好主意,嵌套循环/嵌套映射或类似的方法更为优越,但我需要学习这一点以达到教育目的

为了说明我做了功课,下面是嵌套循环方法:

常数矩阵=[
[3, 6, 7, 34],
[6, 3, 5, 2],
[2, 6, 8, 3]
];
常数transposedMatrix=[]
for(设i=0;i
工作原理:

我们总是从给定的矩阵中取出第一列(
matrix.map(row=>row.shift())
,然后递归地继续:

 [[1, 1, 1],    ->   [[1, 1],    ->  [[1],   ->   [[],
  [2, 2, 2],          [2, 2],         [2],         [],
  [3, 3, 3]]          [3, 3]]         [3]]         []]
然后到达基本情况,矩阵为空(
matrix[0]。length
为0=falsy)并返回一个空数组。现在,在每个步骤中,取出的列都被添加到该数组中,因此它现在是一行:

   [[1, 2, 3],    <-    [[1, 2, 3],    <-  [[1, 2, 3]]   <-  []
    [1, 2, 3],            [1, 2, 3]]    
    [1, 2, 3]]
[[1,2,3],
该版本不会改变原始阵列。您可以更进一步,而不仅仅是功能性的,但这有点过头了:

 const transpose = matrix => (
   (row, col) => row(row)(col)(0)
 )(
    row => col => (x) => x >= matrix[0].length ? [] : [col(col)(x, 0), ...row(row)(col)(x + 1)],
    col => (x, y) => y >= matrix.length ? [] : [matrix[y][x], ...col(col)(x, y + 1)]
 );

我会这样写, 假设矩阵中的所有行具有相同的长度:

  • 检查是否仍有行要处理
  • 从给定索引处的每个列创建一行
  • 将列索引增加1
  • 使用新索引调用转置
  • const transpose=(m,ci=0)=>ci>=m[0]。长度
    ? [] 
    :[m.map(r=>r[ci]),…转置(m,ci+1)]
    ;
    常数矩阵=[
    [3, 6, 7, 34],
    [6, 3, 5, 2],
    [2, 6, 8, 3]
    ];
    console.log(
    转置(矩阵),
    
    )
    这与hitmands的解决方案非常相似,性能可能会降低,但我认为避免使用列索引会稍微干净一些:

    const head=xs=>xs[0]
    const tail=xs=>xs.slice(1)
    常量转置=(m)=>头(m).长度
    ?[m.map(头部),…转置(m.map(尾部))]
    : []
    常数矩阵=[
    [3, 6, 7, 34],
    [6, 3, 5, 2],
    [2, 6, 8, 3]
    ]
    控制台日志(
    转置(矩阵)
    
    )
    我有一个想法,使用
    Maybe
    monad编写
    transpose
    。我将开始使用函数操作,然后重构以清理代码-

    依赖关系-

    const { Just, Nothing } =
      require("data.maybe")
    
    const safeHead = (a = []) =>
      a.length
        ? Just(a[0])
        : Nothing()
    
    const tail = (a = []) =>
      a.slice(1)
    
    没有重构-

    const column = (matrix = []) =>
      matrix.reduce
        ( (r, x) =>
            r.chain(a => safeHead(x).map(x => [ ...a, x ]))
        , Just([]) 
        )
    
    const transpose = (matrix = []) =>
      column(matrix)
        .map(col =>
          [ col, ...transpose(matrix.map(tail)) ]
        )
        .getOrElse([])
    
    使用泛型
    append
    lift2
    -

    const append = (a = [], x) =>
      [ ...a, x ]
    
    const lift2 = f =>
      (mx, my) =>
        mx.chain(x => my.map(y => f(x, y)))
    
    const column = (matrix = []) =>
      matrix.reduce
        ( (r, x) =>
            lift2(append)(r, safeHead(x))
        , Just([])
        )
    
    const transpose = (matrix = []) =>
      column(matrix)
        .map(col =>
          [ col, ...transpose(matrix.map(tail)) ]
        )
        .getOrElse([])
    
    再次使用通用转换器重构列-

    const mapReduce = (map, reduce) =>
      (r, x) => reduce(r, map(x))
    
    const column = (matrix = []) =>
      matrix.reduce
        ( mapReduce(safeHead, lift2(append))
        , Just([]) 
        )
    
    const transpose = (matrix = []) =>
      column(matrix)
        .map(col =>
          [ col, ...transpose(matrix.map(tail)) ]
        )
        .getOrElse([])
    
    transpose
    在每个重构步骤中保持不变-

    transpose
      ( [ [ 1, 2, 3, 4 ]
        , [ 5, 6, 7, 8 ]
        , [ 9, 10, 11, 12 ]
        ]
      )
      // [ [ 1, 5, 9 ]
      // , [ 2, 6, 10 ]
      // , [ 3, 7, 11 ]
      // , [ 4, 8, 12 ]
      // ]
    
    transpose
      ( [ [ 1, 2, 3, 4 ]
        , [ 5 ]
        , [ 9, 10, 11, 12 ]
        ]
      )
      // [ [ 1, 5, 9 ] ]
    

    这看起来真的很好,但是你能给我一些背景吗?解释吗?可能是链接吗?仍然有一张
    地图
    -你在作弊:D@JonasWilms谢谢,太好了。已经被接受为正确答案。我想知道您是否可以添加一个变体,其中出于完整性考虑,不使用
    map
    。@alireza当然。我会lso添加一个非变异版本我看到U combinator:)@user633183老实说,我用一个真正的U combinator函数做这件事失败了…所有的
    x(x).
    都可以替换为
    U(x)
    其中
    U=f=>f(f)
    -在旁注中,此
    转置将删除最后一列。即,在OP中使用
    arrMatrix
    ,输出为
    [[3,6,2],[6,3,6],[7,5,8]
    ;缺少
    ..[34,2,3]
    。这是因为
    matrix.length
    用作常量,所以
    3
    用于行和列中的退出条件。啊,对了,应该是固定的。。。是的,但是U引入了另一个变量。很好而且简洁的解释,兄弟:)比我写的
    转置
    要干净得多。我现在要改变的一件事是退出条件
    head(m).length
    m.every(x=>x.length)
    --
    head(m).当我们想象输入时,length
    很脆弱,比如
    [[1,2,3],[4],[5,6,7]
    。第一个递归调用将是
    [[2,3],[],[6,7]]
    ,其中
    head([])
    未定义的
    --
    m.every(…)
    避免了这个陷阱。@user633183:是的,多年来我已经编写了几个版本的
    转置
    ,但这是我第一次尝试通过递归明确地实现它。毫不奇怪,这会导致更可读的代码。我已经更新了,将您的建议作为备选方案,但这是一个有趣的问题,结果应该是您建议的
    [[1,4,5]]
    ,还是当前的
    [[1,4,5],[2,null,6],[3,null,7]
    和这些格式不正确的(?)数据。这是一个很好的答案,斯科特。我应该先说的。递归是一种很好的药物^ ^我认为
    nulls
    是可以的;它是带有
    未定义的
    的稀疏数组,我们必须注意,即
    [1,2,4]
    。我想用
    也许
    来解决这个问题,并将我的答案添加到这个帖子中。今天晚些时候,我将看看是否可以调整它以更好地处理稀疏数组!除非我试图确保一个完整的函数(正如您出色的回答所做的那样),否则我会假装稀疏数组不存在,并认为提供稀疏数组的人应该得到他们应得的
    const mapReduce = (map, reduce) =>
      (r, x) => reduce(r, map(x))
    
    const column = (matrix = []) =>
      matrix.reduce
        ( mapReduce(safeHead, lift2(append))
        , Just([]) 
        )
    
    const transpose = (matrix = []) =>
      column(matrix)
        .map(col =>
          [ col, ...transpose(matrix.map(tail)) ]
        )
        .getOrElse([])
    
    transpose
      ( [ [ 1, 2, 3, 4 ]
        , [ 5, 6, 7, 8 ]
        , [ 9, 10, 11, 12 ]
        ]
      )
      // [ [ 1, 5, 9 ]
      // , [ 2, 6, 10 ]
      // , [ 3, 7, 11 ]
      // , [ 4, 8, 12 ]
      // ]
    
    transpose
      ( [ [ 1, 2, 3, 4 ]
        , [ 5 ]
        , [ 9, 10, 11, 12 ]
        ]
      )
      // [ [ 1, 5, 9 ] ]