How to print a list of strings using "unwords" in Haskell?
I want to print a list of strings as shown below.
|Name|Country|Age|
------------------
|1 |USA |20 |
|2 |UK |19 |
I was able to achieve this using the following.
printfieldName :: [String] -> String
printfieldName [] = []
printfieldName (x:xs) = "|" ++ x ++ "\t" ++ printfieldName (xs)
Is it possible to achieve this using the built-in "unwords" function. I was able to print it out with "unwords" but couldn't fit |
between words.
a source to share
I see there is extra space between '|' and a word, so you can use this function:
printfieldName x = unwords (map ((++) "|") x) ++ "|"
little explanation:
(++) "|" - creates a function which take prefixes each word with "|", so
(++) "|" "test" -> "|test"
then map
applies this function to the list of words, converting them to["|1", "|USA", "|20", ... ]
then unwords
concatenates them into a string with spaces between words. ++ "|"
need to add the final|
a source to share
First, I would write it like this:
printfieldName [] = []
printfieldName (x:xs) = "|" ++ x ++ "\t" ++ printfieldName xs
Well, actually, no, like this:
concatMap (\x -> '|' : x ++ "\t")
Well, maybe more like:
concatMap (printf "|%s\t")
OK. So can this be done as "unwords"?
-- | 'unwords' is an inverse operation to 'words'.
-- It joins words with separating spaces.
unwords :: [String] -> String
unwords [] = ""
unwords ws = foldr1 (\w s -> w ++ ' ':s) ws
No. But see if you can write concatMap as foldr ...
a source to share
Possibly slightly higher than what you asked, but:
formatTable :: [String] -> [[String]] -> String
formatTable header rows =
formatRow header ++ dashRow ++ concatMap formatRow rows
where formatRow cells = bracket '|' (spread cells)
dashRow = bracket '+' (map (\n -> replicate n '-') widths)
bracket c cells = concatMap (c:) cells ++ (c:"\n")
spread cells = zipWith pad widths cells
pad n s = take n (s ++ repeat ' ')
widths = foldr maxLengths (repeat 0) (header : rows)
maxLengths = zipWith (\c l -> max (length c) l)
Then, for example:
> let h = words "Name Country Age"
> let rows = map words ["1 USA 20", "2 UK 19"]
> h
["Name","Country","Age"]
> rows
[["1","USA","20"],["2","UK","19"]]
> putStr $ formatTable h rows
|Name|Country|Age|
+----+-------+---+
|1 |USA |20 |
|2 |UK |19 |
a source to share