木薯导入的CSV内的查找值

时间:2019-11-16 17:45:05

标签: haskell

我成功使用木薯(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

1 个答案:

答案 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中已经讨论过。