我成功使用木薯(http://hackage.haskell.org/package/cassava)读取了CSV文件:
getData = do
csvData <- BL.readFile "data.csv"
case decodeByName csvData of
Left err -> putStrLn err
Right (_, v) -> V.forM_ v $ \ p ->
putStrLn $ col1 p ++ "," ++ col2 p ++ "," ++ (show $ col3 p) ++ "," ++ (show $ col4 p) ++ "," ++ (show $ col5 p) ++ "," ++ col6 p ++ "," ++ (show $ col7 p) ++ "," ++ (show $ col8 p) ++ "," ++ (show $ col9 p) ++ "," ++ (show $ col10 p)
我实际上需要做的是使用col3
中的值作为在col10
中查找值的键。
有人建议我为此使用Data.Map(https://hackage.haskell.org/package/containers-0.4.0.0/docs/Data-Map.html)中的Map
,但是我不确定该如何处理。
到目前为止,我尝试过的所有方法均无效。我假设您在Map
例中输入Right
,如下所示:
Right (_, v) -> Map (V.forM_ v) ???
但是我仍然坚持如何进行。将不胜感激任何建议。理想情况下,我想修改getData
使其为getData keyToFetch = ...
,并且在keyToFetch
中使用Map
。
答案 0 :(得分:1)
是的,使用Data.Map以 col3 中的值作为键在 col10 中查找值可能是个好主意。
由于我们几乎没有关于col3,col10以及您使用的确切数据类型的数据,因此我将诉诸decodebyName example in the Cassava documentation来适应生成映射对象的想法。该示例基于一个非常简单的{姓名,薪水}记录类型。
构造 case 的两个分支必须返回一个公共类型,在我们的例子中是Data.Map对象,而不是IO ()
操作。幸运的是,error
函数非常灵活,可以伪装成适当的类型。
这将给出以下代码:
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
import qualified Data.Map as M
import Control.Monad (forM_)
data Person = Person
{ name :: !String
, salary :: !Int
} deriving (Show, Ord, Eq) -- need that for Map objects
instance FromNamedRecord Person where
parseNamedRecord r = Person <$> r .: "name" <*> r .: "salary"
-- build a map object:
makeMap :: V.Vector Name -> V.Vector Person -> M.Map String Int
makeMap hdr pvec =
-- with name and salary playing the role of col3 and col10:
let pls = V.toList pvec -- get a list
zls = zip (map name pls) (map salary pls)
in M.fromList zls
showRecord :: String -> Int -> String
showRecord name salary = name ++ " earns " ++ (show salary) ++ " dollars"
main :: IO ()
main = do
csvData <- BL.readFile "salaries.csv"
let ma = case decodeByName csvData of
Left errMsg -> error $ "decodeByName failed: " ++ errMsg
Right (hdr, pvec) -> makeMap hdr pvec
-- print out the Map object:
putStrLn $ "Contents of map object:"
putStrLn $ show ma
putStrLn $ ""
forM_ (M.toList ma) (\(n,s) -> putStrLn $ showRecord n s)
let sal1 = M.lookup "John Doe" ma
putStrLn $ "sal1 = " ++ (show sal1)
--
Contents of map object:
fromList [("Jane Doe",60000),("John Doe",50000)]
Jane Doe earns 60000 dollars
John Doe earns 50000 dollars
sal1 = Just 50000
请注意,由于某些原因,我必须广泛使用普通列表,因为从矢量到地图没有直接的路线,这在SO question中已经讨论过。