二维列表如下:
1 | 2 | 3
- - - - -
4 | 5 | 6
- - - - -
7 | 8 | 9
或纯粹的哈斯克尔
[ [1,2,3], [4,5,6], [7,8,9] ]
diagonals [ [1,2,3], [4,5,6], [7,8,9] ]
的预期输出为
[ [1], [4, 2], [7, 5, 3], [8, 6], [9] ]
写allDiagonals
(包括反对角线)是微不足道的:
allDiagonals :: [[a]] -> [[a]]
allDiagonals xss = (diagonals xss) ++ (diagonals (rotate90 xss))
StackOverflow上的类似问题
Hoogle
搜索[[a]] -> [[a]]
没有给我带来任何有趣的结果。
独立思考
我认为索引遵循基数x中的一种计数,其中x是矩阵中的维数,请看:
1 | 2
- - -
3 | 4
对角线为[ [1], [3, 2], [4] ]
1
可以在matrix[0][0]
3
可以在matrix[1][0]
2
可以在matrix[0][1]
1
可以在matrix[1][1]
这类似于在基数2中计数到3,即矩阵大小减1。但这太过模糊,无法翻译成代码。
答案 0 :(得分:8)
从universe-base-1.0.2.1开始,您只需调用diagonals
函数:
Data.Universe.Helpers> diagonals [ [1,2,3], [4,5,6], [7,8,9] ]
[[1],[4,2],[7,5,3],[8,6],[9]]
完整的实现如下:
diagonals :: [[a]] -> [[a]]
diagonals = tail . go [] where
-- it is critical for some applications that we start producing answers
-- before inspecting es_
go b es_ = [h | h:_ <- b] : case es_ of
[] -> transpose ts
e:es -> go (e:ts) es
where ts = [t | _:t <- b]
关键的想法是我们保留两个列表:我们尚未开始检查的矩形块,以及我们拥有的五边形块(左上三角形切割的矩形!)。对于五边形块,从每个列表中挑选出第一个元素会给我们另一个对角线。然后我们可以在删除该对角线后,从未经检查的矩形块中添加一个新行到
。实现可能看起来有点不自然,但它的目的是非常高效和懒惰:我们对列表做的唯一事情是将它们分解为头尾,所以这应该是O(n)in矩阵中元素的总数;我们在完成解构后立即生成元素,因此它对垃圾收集非常懒惰/友好。它也适用于无限大的矩阵。
(我推出这个版本只是为了你:你可以得到的最接近的东西是使用diagonal
,这只会给你[1,4,2,7,5,3,8,6,9]
没有你想要的额外结构。)
答案 1 :(得分:4)
这是一个递归版本,假设输入总是格式正确:
diagonals [] = []
diagonals ([]:xss) = xss
diagonals xss = zipWith (++) (map ((:[]) . head) xss ++ repeat [])
([]:(diagonals (map tail xss)))
它从列到列递归地工作。来自一列的值与来自矩阵的对角线组合,减少一列,移动一行以实际获得对角线。希望这种解释是有道理的。
例如:
diagonals [[1,2,3],[4,5,6],[7,8,9]]
= zipWith (++) [[1],[4],[7],[],[],...] [[],[2],[5,3],[8,6],[9]]
= [[1],[4,2],[7,5,3],[8,6],[9]]
另一个版本适用于行而不是列,但基于相同的想法:
diagonals [] = repeat []
diagonals (xs:xss) = takeWhile (not . null) $
zipWith (++) (map (:[]) xs ++ repeat [])
([]:diagonals xss)
与指定的结果相比,生成的对角线反转。这当然可以通过应用map reverse
来解决。
答案 2 :(得分:2)
这是一种方法:
f :: [[a]] -> [[a]]
f vals =
let n = length vals
in [[(vals !! y) !! x | x <- [0..(n - 1)],
y <- [0..(n - 1)],
x + y == k]
| k <- [0 .. 2*(n-1)]]
例如,在GHCi中使用它:
Prelude> let f vals = [ [(vals !! y) !! x | x <- [0..(length vals) - 1], y <- [0..(length vals) - 1], x + y == k] | k <- [0 .. 2*((length vals) - 1)]]
Prelude> f [ [1,2,3], [4,5,6], [7,8,9] ]
[[1],[4,2],[7,5,3],[8,6],[9]]
假设一个正方形n
x n
矩阵,将会有n + n - 1
对角线(这是k
迭代的对象),对于每个对角线,不变量是行和列索引总和为对角线值(从左上角的零索引开始)。您可以交换商品访问顺序(与!! y !! x
交换!! x !! y
)以反转矩阵上的光栅扫描顺序。
答案 3 :(得分:1)
另一个解决方案:
diagonals = map concat
. transpose
. zipWith (\ns xs -> ns ++ map (:[]) xs)
(iterate ([]:) [])
基本上,我们转向
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
到
[[1], [2], [3]]
[[] , [4], [5], [6]]
[[] , [] , [7], [8], [9]]
然后是transpose
和concat
列表。对角线的顺序相反。
但这不是很有效,也不适用于无限列表。