在Haskell中求矩阵的所有对角线
二维列表如下所示:在Haskell中求矩阵的所有对角线,haskell,matrix,Haskell,Matrix,二维列表如下所示: 1 | 2 | 3 - - - - - 4 | 5 | 6 - - - - - 7 | 8 | 9 还是纯哈斯克尔 [ [1,2,3], [4,5,6], [7,8,9] ] 对角线[[1,2,3],[4,5,6],[7,8,9]]的预期输出为 [ [1], [4, 2], [7, 5, 3], [8, 6], [9] ] 编写所有对角线(包括反对角线)就很简单了: allDiagonals :: [[a]] -> [[a]] allDiagonals xss =
1 | 2 | 3
- - - - -
4 | 5 | 6
- - - - -
7 | 8 | 9
还是纯哈斯克尔
[ [1,2,3], [4,5,6], [7,8,9] ]
对角线[[1,2,3],[4,5,6],[7,8,9]]的预期输出为
[ [1], [4, 2], [7, 5, 3], [8, 6], [9] ]
编写所有对角线
(包括反对角线)就很简单了:
allDiagonals :: [[a]] -> [[a]]
allDiagonals xss = (diagonals xss) ++ (diagonals (rotate90 xss))
我对这个问题的研究
StackOverflow的类似问题
- 这个问题与Python中的相同问题有关,但是Python和Haskell非常不同,所以这个问题的答案与我无关
- 这个问题和答案是用Haskell写成的,但只涉及中心对角线
Hoogle
搜索[[a]]->[[a]]
没有给我任何有趣的结果
独立思考
我认为索引遵循基数x中的一种计数,其中x是矩阵中的维数,请看:
1 | 2
- - -
3 | 4
对角线是[[1],[3,2],[4]]
1
可在矩阵[0][0]
3
可在矩阵[1][0]
2
可在矩阵[0][1]
1
可在矩阵[1][1]
这类似于从基数2到3的计数,即矩阵大小减1。但这太模糊了,无法翻译成代码。这里有一种方法:
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)]]
f::[[a]]->[[a]]
f VAL=
设n=长度VAL
在[[(vals!!y)!!x | x中,这里是一个递归版本,假设输入总是格式良好的:
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)
与指定的结果相比,生成的对角线是反向的。当然,这可以通过应用映射反向
导入数据。列表来修复
import Data.List
rotate90 = reverse . transpose
rotate180 = rotate90 . rotate90
diagonals = (++) <$> transpose . zipWith drop [0..]
<*> transpose . zipWith drop [1..] . rotate180
rotate90=反向转置
旋转180=旋转90。旋转90
对角线=(++)转置.zipWith drop[0..]
转置。带下拉[1..]的拉链。旋转180
它首先获取主([1,5,9]
)和上对角线([2,6]
和[3]
),然后获取下对角线:[8,4]
和[7]
如果您关心排序(即,您认为应该说[4,8]
而不是[8,4]
),请在最后一行插入映射反向。
。从开始,您可以简单地调用该函数:
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]
对角线::[[a]]->[[a]]
对角线=尾部。转到[]哪里
--对于某些应用程序,我们开始生成答案是至关重要的
--检查前_
go b es|=[h | h:uu转置ts
e:es->go(e:ts)es
式中,ts=[t | |:t彼此的解决方案:
diagonals = map concat
. transpose
. zipWith (\ns xs -> ns ++ map (:[]) xs)
(iterate ([]:) [])
基本上,我们转向
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
进入
然后transpose
和concat
列表。对角线的顺序相反
但是这不是很有效,也不适用于无限列表。谢谢,我对这个响应的速度和清晰性印象深刻。但是请将f
重命名为diagonals
,因为Haskell已经有了足够多的单字母名称;但是我碰巧偏爱这个字母:p--->对不起,我不得不说我不喜欢“我不喜欢这个解决方案。首先,列表中有太多的!!
,应该尽可能避免出现这种情况(与向量不同)。其次,它会循环y@chi这些都是正确的观点。我不反对其中任何一点。它们并不影响我对这个特定解决方案的看法,这就是为什么我仅将其限定为“单向”要解决它。请随意优化它。Haskell更自然的思考方式是:给定第一行和由其余行组成的矩阵上的对角线的结果,我们如何在整个原始矩阵上构造对角线的结果?数学我实际上不关心排序rotate180
似乎有点奇怪。不会映射反向。反向
做这个把戏吗?使用tail
在某种程度上是必要的吗?@dfeuer不是必要的;但总是从空列表开始似乎并不是非常有用。有其他方法跳过它吗?@dfeuer几乎可以肯定!你有什么想法吗?我只是不喜欢usi除非懒惰需要,否则使用部分函数来实现全部函数。在这种情况下,我猜您可以专门处理第一步来避免它,但我没有尝试过。
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[[1], [2], [3]]
[[] , [4], [5], [6]]
[[] , [] , [7], [8], [9]]