Reputation: 365
I need to print out a matrix in haskell so it looks like this:
main> putStr (showMat [[1,-500,-4], [100,15043,6], [5,3,10]])
1 -500 -4
100 15043 6
5 3 10
So far I have come up with this:
type Matrix a = [[a]]
type IntMat = Matrix Integer
showMat :: IntMat -> String
showMat [] = ""
showMat ((y:ys):xs) = (printRow (rowmaxs) (elements) (y:ys)) ++ "\n" ++ showMat xs
where rowmaxs = rowMaxs ((y:ys):xs) ; elements = elementLengths (y:ys)
rowMaxs :: IntMat -> [Int]
rowMaxs [] = []
rowMaxs (x:xs) = [length (show (maximum (x)))] ++ (rowMaxs xs)
elementLengths :: [Integer] -> [Int]
elementLengths [] = []
elementLengths (y:ys) = [length (show y)] ++ (elementLengths ys)
printRow :: [Int] -> [Int] -> [Integer] -> String
printRow [] (a:as) (y:ys) = ""
printRow (z:zs) (a:as) [] = ""
printRow [] [] (y:ys) = ""
printRow [] [] [] = ""
printRow (z:zs) (a:as) (y:ys) = addSpaces (z-a) ++ show y ++ [' '] ++ printRow zs as ys
addSpaces :: Int -> String
addSpaces 0 = ""
addSpaces n = " " ++ addSpaces (n-1)
Which returns this:
Main> putStr (showMat [[1,23,1],[23,56,789],[1234,0,1]])
1 23 1
23 56
1234
I can see the loss of the elements at the end of rows is due to the cases in the printRow function, but I don't know how to fix it. Also the characters don't take into account the ones printed before them. Any help on how I can fix this would be appreciated.
Upvotes: 1
Views: 4264
Reputation: 8395
I've written a small script some time ago that takes a tab-separated table (CSV style) and prettyprints it to the console. I've extracted the relevant parts and uploaded the source code here. For example, given your input
m = [[1,23,456],[78,-90,123],[4567,8,9]]
putStrLn $ showMat m
will make it into
1 -500 -4
100 15043 6
5 3 10
There's also a function (commented out) at the very bottom if you want left alignment.
Upvotes: 3
Reputation: 47052
In showMat
you calculate rowmaxs
and elements
anew for each row. In particular, rowmaxs
has an element for each row left in the matrix, but printRow
uses it as meaning something for each column of the matrix.
Edit: Here's a slightly better version of showMat
:
showMat :: IntMat -> String
showMat rows = concat (map perRow rows)
where rowmaxs = rowMaxs rows
perRow cols = printRow rowmaxs elements cols ++ "\n"
where elements = elementLengths cols
It's still buggy --- rowMaxs
(tries to) calculate the maximum length of the numbers in each row, but you really want the maximum length of the numbers in each column. One consequence of that is that you occasionally pass negative numbers to addSpaces
, which doesn't cope terribly well, so here's a version of addSpaces
that behaves more gracefully:
addSpaces :: Int -> String
addSpaces n = replicate n ' '
So now we get this:
*Main> putStr (showMat [[1,23,1],[23,56,789],[1234,0,1]])
1 23 1
23 56 789
1234 0 1
Better, but not yet working properly.
I have not fixed all the bugs in your code because I sense you are still learning and need the experience of finding them for yourself.
I advise using map
/zipWith
/zipWith3
instead of explicitly writing the recursion, as it makes code easier to understand.
Upvotes: 1