Haskell - 如何将矩阵(二维数组)分组

Lou*_*ran 2 haskell matrix

我在下面有一个二维矩阵:

mat = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
Run Code Online (Sandbox Code Playgroud)

我想把它翻译成4组:

output = [[1,2,5,6],[3,4,7,8],[9,10,13,14],[11,12,15,16]]
Run Code Online (Sandbox Code Playgroud)

在 Java 或 Python 等其他(命令式)编程语言中,我可以轻松创建 4 个新列表,并从(i,j)每个子矩阵的左上角开始迭代以添加元素。但在 Haskell 中,我不知道如何实现我想要的因为它不支持 for 循环并且递归循环(x:xs)似乎对这种情况没有帮助。

在此处输入图片说明

Dav*_*her 5

It's useful to write chunksOf which breaks a list into parts, each of a given size.

chunksOf :: Int -> [a] -> [[a]]
chunksOf _ [] = []
chunksOf n xs = ys : chunksOf n zs
  where
    (ys, zs) = splitAt n xs
Run Code Online (Sandbox Code Playgroud)

For example:

> chunksOf 2 "potato"
["po","ta","to"]
Run Code Online (Sandbox Code Playgroud)

(If you know about unfoldr, you can also write chunksOf nicely using that.)

We can use chunksOf 2 to get groups of two rows each, [[1,2,3,4], [5,6,7,8]] and [[9,10,11,12], [13,14,15,16]].

From these we want to group the columns - we can do this by transposing, grouping rows, then transposing each group back again.

(transpose is in Data.List.)

For example, on the first row group, we transpose to get

[[1, 5], [2, 6], [3, 7], [4, 8]]
Run Code Online (Sandbox Code Playgroud)

Then chunksOf 2 gives us

[[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
Run Code Online (Sandbox Code Playgroud)

Then we map transpose to get

[[[1, 2], [5, 6]], [[3, 4], [7, 8]]]
Run Code Online (Sandbox Code Playgroud)

So now we have 2x2 submatrices and the only thing left to get what you wanted is to flatten each one with concat.

Putting it all together:

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
Run Code Online (Sandbox Code Playgroud)