Reputation: 21
I've got some data in txt file which looks like this:
[Just 3, Nothing, Just 1, Nothing] [Nothing, Nothing, Nothing, Nothing] [Nothing, Nothing, Just 4, Nothing] [Nothing, Just 3, Nothing, Nothing]
What I need is to have list of lists containing above values as integers e.g.
[[3,0,1,0],[0,0,0,0],....]
And so on. Do you have any idea how to do it properly? I can replace "nothing" by 0 and drop "Just" part but it will stay as a single string.
Upvotes: 2
Views: 520
Reputation: 725
Just an alternate version that uses read
:
import Data.List.Split (splitOn)
import Data.Maybe (fromMaybe)
main :: IO ()
main = do
s <- readFile "lists.txt"
let xs = map (\s' -> map (fromMaybe 0) (read (s' ++ "]"))) . init . splitOn "]" $ s
print xs
The idea is simple: first, the file contents are read as a String
and bound to s
. Then, s
is parsed to a list of integers ([Int]
) which is bound to xs
. In order to do that, the following steps are taken:
splitOn "]"
: splits the input string s
generating a list of strings ([String]
). Each element misses the character ']'
in the end. The last element of this list is an undesirable "\n"
. The resulting list is:
["[Just 3, Nothing, Just 1, Nothing"," [Nothing, Nothing, Nothing, Nothing", ..., "\n"]
init
: removes the unwanted "\n".
map (\s' -> map (fromMaybe 0) (read (s' ++ "]")))
: applies to each string element the enclosed lambda function, which does:
read (s' ++ "]")
: append the missing ']'
to the string and parses it to a list of Maybe
s (Num a => [Maybe a]
). Note that we do not need to explicitly specify a type for read
because GHC can infer it from the use of fromMaybe 0
(see below).map (fromMaybe 0)
: apply the function fromMaybe 0
on each element of the list, which returns v
when Just v
; and 0
, otherwise.That way you can get a list of integer lists using read
.
Upvotes: 0
Reputation: 2983
The correct way to do this is probably to use a parser library like Text.Parsec
. That being said, here's a quick and hacky way to do it not unlike what a python programmer might come up with. The idea is to massage the input string into a form that read
will parse for us.
{-# LANGUAGE OverloadedStrings #-}
import Prelude hiding (null)
import Data.Text (snoc, pack, unpack, splitOn, strip, null)
import Data.Maybe (fromMaybe)
import System.IO
parse :: String -> [[Maybe Int]]
parse = map read . map unpack . map (flip snoc ']') . filter (not . null) . map strip . splitOn "]" . pack
main :: IO ()
main = do
input <- readFile "myfile.txt" -- input = "[Just 3, Nothing, Just 1, Nothing] [Nothing, Nothing, Nothing, Nothing] [Nothing, Nothing, Just 4, Nothing] [Nothing, Just 3, Nothing, Nothing]"
putStrLn . show $ map (map (fromMaybe 0)) (parse input)
The parse
method works like this:
pack
converts a String
value into a Text
valuesplitOn "]"
does exactly what you thinkmap strip
removes leading and trailing whitespacefilter (not . null)
removes empty strings (there's one at the end)map (flip snoc ']')
append the "]" character back to the end of each stringmap unpack
converts each Text
value back to a String
valuemap read
parses each String
value into a [Maybe Int]
Upvotes: 1