csv-enumerator - 保持地图未分类?

时间:2012-02-25 11:54:35

标签: haskell csv

我选择了csv-enumerator包来解析大量的CSV文件任务。 输入文件确实包含标题,因此为行表示选择了地图类型。 MapRow是Data.Map ByteString ByteString的别名,具体而言。

问题在于map是由csv-enumerator代码深处的键(列名)自动排序的 - 在localy-scoped toMapCSV函数中使用Data.Map.fromList按键排序元素,所以简单的monkey-patch不是可能的。

我需要保留输出CSV的列顺序。 不幸的是,我目前的解决方案相当复杂,即。单独读取标题并重新排序一次读取MapRow:

import Data.CSV.Enumerator
import qualified Data.Map as M
import Data.Either
import Control.Monad
...
csvMode = CSVS { csvSep = ';'
               , csvQuoteChar = Just '"'
               , csvOutputQuoteChar = Just '"'
               , csvOutputColSep = ';'
               }
...
updateCSV :: FilePath -> IO (Either SomeException Int)
updateCSV fn = do
  ...
  csv <- readCSVFile csvMode fn >>= return . (either (const []) (id :: [MapRow]->[MapRow]))
  hdr <- readCSVFile csvMode fn >>= return . head .(either (const []) (id :: [Row]->[Row]))
  ...
  -- reorder MapRow
  outMapRow=M.fromAscList $ map (\k -> (k, (M.!) (head csv) k)) hdr
  ...
  • 有一种更简单的方法来保持原始CSV文件的列顺序吗?
  • 更改csv-enumerator源不是一个选项
  • 我想在实际代码中提到输入csv文件由foldCSVFile处理,即。除了哈斯克尔的懒惰之外,“逐行”

1 个答案:

答案 0 :(得分:0)

由于没有比csv-enumerator更完整的CSV解析模块和用于行表示的Data.Map丢失列的原始顺序,我不得不使用关联列表并实现自定义函数以进行元素更新,在assoc之间进行转换。列表和普通列表等。幸运的是标准的Data.List(GHC.List)至少包含查找和zip / unzip函数。

  1. 第一行csv文件从IO操作中提取一次

    标题&lt; - readCSVFile ...&gt;&gt; =返回。头......

  2. 使用foldCSVFile

    解析csv文件的内容

    linesCount&lt; - foldCSVFile ...(funToIterIO ...)0

  3. 迭代函数使用从Row转换的关联列表[(Field,Field)]并在写入输出文件之前将其转换回来

    让assocRow = zip header ...

    让updatedARow =调整trans“列名”assocRow

    - 写下更新的值

    outputRow ... $ foldr((:)。snd)[] updatedARow

  4. 尽管需要编写更多代码并消耗更多时间,但所有工作都按预期工作:(