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 ] ]