我正在尝试阅读和分析一个巨大的CSV文件。我使用了来自cassava的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实例正在执行,那么程序可以很好地单次传递CSV数据并且不会消耗太多内存。有没有办法将foldl融合在一起?那就是
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
:
take
并且foldl以空地图开头。
内存使用量随着元素数量{{1}} d的增加而增加,无论是否有优化。
答案 0 :(得分:2)
是的,您确实可以将四个折叠融合在一起,但您必须手动完成。您可以尝试自己编写逻辑,也可以使用库(如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