如何转置2D矢量

时间:2019-04-10 05:25:19

标签: haskell

如何在Haskell中表示二维数组整数,以便我可以在O(1)或O(logN)中使用(i,j)访问任何元素?

使用Data.Array和Data.Vector进行定义有什么区别?哪个更实用

data Matrix = Vector (Vector Int)

如果我定义如上,那么如何制作一个可以对此矩阵进行转置的函数?

例如:换位[[1,2,3],[4,5,6],[7,8,9]]将返回[[1,4,7],[2,5,8],[3,6,9]]

2 个答案:

答案 0 :(得分:4)

ArrayVector具有相似的内部表示,但是Array的API是专为索引操作(通过Ix类)而Vector具有一个更像列表的界面,并依靠融合来有效地组合这些操作。两者都允许O(1)随机访问。

顺便说一句,Array中有base,而Vector定义了vector包,因此如果您想避免使用Array另一个依赖项。

在任何一种情况下,都可以根据索引来实现换位。使用Array可能会更自然一些,import Data.Array (Array, (!)) import qualified Data.Array as Array example1 :: Array (Int, Int) Char example1 = Array.array ((0, 0), (1, 1)) [ ((0, 0), 'a'), ((0, 1), 'b') , ((1, 0), 'c'), ((1, 1), 'd') ] example2 :: Array (Int, Int) Int example2 = Array.listArray ((0, 0), (2, 2)) [ 1, 2, 3 , 4, 5, 6 , 7, 8, 9 ] transpose :: Array (Int, Int) a -> Array (Int, Int) a transpose a = Array.array bounds [ ((row, col), a ! (col, row)) | row <- [minRow .. maxRow] , col <- [minCol .. maxCol] ] where -- Note that indices need not be 0-based. bounds@((minRow, minCol), (maxRow, maxCol)) = Array.bounds a transpose example1 == Array.array ((0, 0), (1, 1)) [ ((0, 0), 'a'), ((0, 1), 'c') , ((1, 0), 'b'), ((1, 1), 'd') ] Array.elems (transpose example2) == [ 1, 4, 7 , 2, 5, 8 , 3, 6, 9 ] 可以成对索引以创建保证为矩形的2D数组:

Vector

对于import Data.Vector (Vector, (!)) import qualified Data.Vector as Vector -- Does not handle non-square arrays, nor -- those with an outer dimension of zero. transpose :: Vector (Vector a) -> Vector (Vector a) transpose v = Vector.fromList [ Vector.fromList [ v ! col ! row | col <- [0 .. maxCol] ] | row <- [0 .. maxRow] ] where maxRow = Vector.length v - 1 maxCol = Vector.length (v ! 0) - 1 ,您只需索引两次:

Vector (Vector a)

请注意,不能保证fromList [ fromList ['a', 'b'] , fromList ['c'] ] 不是“锯齿状”的2D数组,其中内部向量的长度是不同的,例如:

Vector (Vector a)

这仅意味着您需要检查输入的格式是否正确。此外,Array (Int, Int) a在内存中不是连续的:它是指向元素向量的指针的数组,而Vector是单个内存块,因此Vector a对此造成了恒定的开销表示。如果需要考虑性能,则可以通过使用长度为rows * cols的{​​{1}}并将其手动索引为row * cols + col来删除此间接寻址;这实际上是Array通过Ix内部执行的操作。

答案 1 :(得分:0)

如果您使用的是平面向量,那么比坚持使用vector包可能是一个好主意。但是,如果确实需要1个以上的维,建议您使用一个处理数组的库。我是massiv的作者,因此我有些偏颇,但这是我推荐的库。我绝对不建议您使用array库,尽管它已与ghc连接,但其接口非常有限且有点混乱。

例如,如果您想用massiv转置2d矩阵,您可以这样做:

λ> arr <- resizeM (Sz2 3 3) (1 ... 9)
λ> arr
Array D Seq (Sz (3 :. 3))
  [ [ 1, 2, 3 ]
  , [ 4, 5, 6 ]
  , [ 7, 8, 9 ]
  ]
λ> let arrUnboxed = computeAs U $ transpose arr
λ> arrUnboxed
Array U Seq (Sz (3 :. 3))
  [ [ 1, 4, 7 ]
  , [ 2, 5, 8 ]
  , [ 3, 6, 9 ]
  ]
λ> arrUnboxed ! (2 :. 1)
6

请注意,直到调用compute为止,都没有发生内存分配,但是一旦计算出来,就只能在O(1)中对其进行索引。同样,如果您应用setComp Par arr,整个操作将自动为您并行化。

如果需要入门,文档中还有更多示例。