首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >哈斯克尔木薯(Data.Csv):忽略缺少的列/字段

哈斯克尔木薯(Data.Csv):忽略缺少的列/字段
EN

Stack Overflow用户
提问于 2021-02-20 15:02:27
回答 1查看 228关注 0票数 2

如何设置木薯以忽略缺少的列/字段,并用默认值填充相应的数据类型?考虑一下这个例子:

代码语言:javascript
复制
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}

import           Data.ByteString.Lazy.Char8
import           Data.Csv
import           Data.Vector
import           GHC.Generics

data Foo = Foo { 
      a :: String
    , b :: Int
    } deriving (Eq, Show, Generic)
    
instance FromNamedRecord Foo

decodeAndPrint :: ByteString -> IO ()
decodeAndPrint csv = do
    print $ (decodeByName csv :: Either String (Header, Vector Foo))

main :: IO ()
main = do
    decodeAndPrint "a,b,ignore\nhu,1,pu"  -- [1]
    decodeAndPrint "ignore,b,a\npu,1,hu"  -- [2]
    decodeAndPrint "ignore,b\npu,1"     -- [3]

[1][2]工作得很好,但是[3]失败了

代码语言:javascript
复制
Left "parse error (Failed reading: conversion error: no field named \"a\") at \"\""

如何使decodeAndPrint能够处理这种不完整的输入?

当然,我可以操作输入字节串,但是也许有一个更优雅的解决方案。

由于Daniel的输入,解决方案如下:

代码语言:javascript
复制
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}

import           Control.Applicative
import           Data.ByteString.Lazy.Char8
import           Data.Csv
import           Data.Vector
import           GHC.Generics

data Foo = Foo { 
      a :: Maybe String
    , b :: Maybe Int
    } deriving (Eq, Show, Generic)
    
instance FromNamedRecord Foo where
    parseNamedRecord rec = pure Foo
        <*> ((Just <$> Data.Csv.lookup rec "a") <|> pure Nothing)
        <*> ((Just <$> Data.Csv.lookup rec "b") <|> pure Nothing)

decodeAndPrint :: ByteString -> IO ()
decodeAndPrint csv = do
    print $ (decodeByName csv :: Either String (Header, Vector Foo))

main :: IO ()
main = do
    decodeAndPrint "a,b,ignore\nhu,1,pu"  -- [1]
    decodeAndPrint "ignore,b,a\npu,1,hu"  -- [2]
    decodeAndPrint "ignore,b\npu,1"       -- [3]
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-20 19:35:51

(警告:完全未经测试!代码仅用于思想传递,不适用于任何用途等)

FromNamedRecord所要求的FromNamedRecord类型是一个Alternative,所以只需使用(<|>)就可以了。

代码语言:javascript
复制
instance FromNamedRecord Foo where
    parseNamedRecord rec = pure Foo
        <*> (lookup rec "a" <|> pure "missing")
        <*> (lookup rec "b" <|> pure 0)

如果您以后想知道字段是否存在,请让您的字段足够丰富,以便记录:

代码语言:javascript
复制
data RichFoo = RichFoo
    { a :: Maybe String
    , b :: Maybe Int
    }

instance FromNamedRecord Foo where
    parseNamedRecord rec = pure RichFoo
        <*> ((Just <$> lookup rec "a") <|> pure Nothing)
        <*> ((Just <$> lookup rec "b") <|> pure Nothing)
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66293020

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档