簡體   English   中英

Haskell 木薯(Data.Csv):忽略缺少的列/字段

[英]Haskell cassava (Data.Csv): Ignore missing columns/fields

如何設置木薯以忽略缺失的列/字段並使用默認值填充相應的數據類型? 考慮這個例子:

{-# 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]失敗了

Left "parse error (Failed reading: conversion error: no field named \"a\") at \"\""

我怎樣才能讓decodeAndPrint能夠處理這個不完整的輸入?

我當然可以操縱輸入字節串,但也許有更優雅的解決方案。


感謝以下 Daniel Wagner 輸入的解決方案

{-# 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]

(警告:完全未經測試,代碼僅用於思想傳播,不適合任何用途。等等等等)

FromNamedRecord要求的Parser類型是Alternative ,因此只需使用(<|>)設置默認值。

instance FromNamedRecord Foo where
    parseNamedRecord rec = pure Foo
        <*> (lookup rec "a" <|> pure "missing")
        <*> (lookup rec "b" <|> pure 0)

如果您想稍后知道該字段是否存在,請使您的字段足夠豐富以記錄:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM