下面有一个二维矩阵:
mat = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
我想把它翻译成4组:
output = [[1,2,5,6],[3,4,7,8],[9,10,13,14],[11,12,15,16]]
在 Java 或 Python 等其他(命令式)编程语言中,我可以轻松地创建 4 个新列表并从每个子矩阵的左上角位置 (i,j)
开始迭代以将元素添加到. 但是在 Haskell 中,我不知道如何实现我想要的,因为它不支持循环,递归循环 (x:xs)
似乎对这种情况没有帮助。
最佳答案
编写 chunksOf
是很有用的,它将一个列表分成几部分,每个部分
给定大小。
chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf n xs = ys : chunksOf n zs
where
(ys, zs) = splitAt n xs
例如:
> chunksOf 2 "potato"
["po","ta","to"]
(如果你了解unfoldr
,你也可以写的很好chunksOf
使用那个。)
我们可以使用 chunksOf 2
来获取每行两行的组,[[1,2,3,4], [5,6,7,8]]
和 [[9,10,11,12], [13,14,15,16]]
。
从这些我们想要对列进行分组 - 我们可以通过 转置、分组行,然后再次转置每组。
(转置
在Data.List中。)
例如,在第一行组,我们转置
得到
[[1, 5], [2, 6], [3, 7], [4, 8]]
然后 chunksOf 2
给了我们
[[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
然后我们映射转置
得到
[[[1, 2], [5, 6]], [[3, 4], [7, 8]]]
所以现在我们有了 2x2 子矩阵,剩下的就是得到你想要的
想要的是用 concat
把每一个都压平。
综合起来:
f :: Int -> [[a]] -> [[a]]
f size = map concat . subMatrices size
subMatrices :: Int -> [[a]] -> [[[a]]]
subMatrices size = concatMap subsFromRowGroup . rowGroups
where
rowGroups = chunksOf size
subsFromRowGroup = map transpose . chunksOf size . transpose
https://stackoverflow.com/questions/64132032/