代码之家  ›  专栏  ›  技术社区  ›  Henricus V.

haskell中多重foldl'的融合

  •  2
  • Henricus V.  · 技术社区  · 6 年前

    我正试图阅读和分析一个巨大的csv文件。我用过 Data.Csv.Streaming 从木薯中提取,并按以下顺序应用功能:

    Data.ByteString.Lazy.readFile -- Gives lazy stream
    Data.Csv.Streaming.decodeByname -- Gives Either String (Header Records t)
    \(Right (_, v)) -> v -- Gives right side of either (Records t)
    Data.Foldable.toList -- Gives [t]
    

    之后,程序进入分析阶段,并执行 (这一点非常重要)以下各项的不同实例(即使用不同的过滤器)

    filter -- Result of toList is applied through a filter
    map
    Data.Foldable.foldl' -- Does bin counting using a map. The map has at most 60 keys.
    

    但是,在尝试加载整个csv文件时,程序似乎占用了大量内存。

    如果我只有一个foldl'executing的实例,那么这个程序就可以很好地单次传递csv数据,而且不会消耗那么多内存。有没有办法把这些东西融合在一起?也就是说,

    x = foldl' f Map.empty $ filter cx li
    y = foldl' f Map.empty $ filter cy li
    ...
    

    并强制它在一次传递中执行。

    编辑:以下函数用于 foldl 具有 Data.Map.Strict 作为 Map :

    bincollect :: Ord a => Num b => Map.Map a b -> a -> Map.Map a b
    bincollect !m !key = Map.insertWith (+) key 1 m
    

    foldl以一个空映射开始。

    内存使用量随着元素数量的增加而增加 take d是否启用优化。

    1 回复  |  直到 6 年前
        1
  •  2
  •   oisdk    6 年前

    是的,你确实可以把四个折叠部分熔合在一起,但你得用手来做。你可以试着自己写出逻辑,或者你可以使用一个库(比如 foldl 来帮忙。例如,您可以将bincollect变成一个折叠:

    bincollect :: (Ord a, Num b) => Fold a (Map.Map a b)
    bincollect = Fold (\m key -> Map.insertWith (+) key 1 m) Map.empty id
    

    然后,可以使用 prefilter :

    x = prefilter cx bincollect
    

    最后,您可以使用 Applicative 实例:

    (w,x,y,z) = fold ((,,,) <$> prefilter cw bincollect
                            <*> prefilter cx bincollect
                            <*> prefilter cy bincollect
                            <*> prefilter cz bincollect)
                     input