首页 > 解决方案 > Haskell parsing input

问题描述

I'm trying to parse Int values from IO to a list of list.
t -> no of input test cases
n -> no of elements in the array
k -> sum value of array/any int value

input:

3               -> t (no of input test cases)
4 3              -> n, k (no of arr, some int value)
-1 -3 4 2        -> arr
4 2              -> n, k (no of arr, some int value)
0 -1 2 1         -> arr
5 2              -> n, k (no of arr, some int value)
2 1 0 -2 -1      -> arr

Expected output: [[3,-1,-3,4,2],[2,0,-1,2,1],[2,2,1,0,-2,-1]] -> list of list

import System.IO

solve :: [Int] -> String
solve (k:arr) 
    | len < k   = "YES"
    | otherwise = "NO"
    where
        len = length $ filter (<=0) arr

parseIn :: IO() -> [[Int]]
parseIn = do
    t <- readLn :: IO Int
    inputs <- forM_ [1..t] $ (\_ -> do
        [n,k] <- map (read :: String -> Int) . words . getLine
        arr   <- map (read :: String -> Int) . words . getLine
        return [k:arr])
    return inputs

main = interact $ unlines . map solve . parseIn

Can someone please help me solve this?

标签: haskell

解决方案


I don't know exactly, what you are trying to achieve with the solve function, but for your given example and the expected output, this should do.

The important bit is the inputNumbers function that retries reading numbers from the command line until a valid input is entered.

The readNumbers function uses the monadic properties of Maybe. As soon as one of the words can not be read as an Int, the rest is skipped and Nothing is returned. readLn is not very useful here, as you want to enter the list of numbers as a space seperated string and not in Haskell's list format, e.g. 1 2 3 instead of [1, 2, 3].

import Text.Read (readMaybe)
import Control.Monad (forM)

-- tries to parse a space seperated list of given
-- number of numbers from the given string
readNumbers :: Int -> String -> Maybe [Int]
readNumbers n input
    | length split == n = mapM readMaybe split -- try to read numbers
    | otherwise = Nothing
  where split = words input -- split at spaces

inputNumbers :: Int -> IO [Int]
inputNumbers n = do
    -- read one line from the commandline
    input <- getLine
    -- try to parse list of numbers of given length
    case readNumbers n input of
        Just nums -> return nums -- return the parsed numbers
        Nothing -> do
            -- invalid input: retry
            putStrLn $ "Invalid input: " ++ input
            inputNumbers n

main :: IO ()
main = do
    -- read the number of tries
    [t] <- inputNumbers 1
    arrs <- forM [1..t] $ \_ -> do
        -- read the list length and an int value
        [n, k] <- inputNumbers 2
        -- read the list of the given length
        arr <- inputNumbers n
        -- return the read list with prepended k
        return $ k:arr
    -- print result
    print arrs

推荐阅读