如何将“1”和“2”的流分成组?

时间:2015-10-17 03:42:55

标签: haskell

想象一下,我有一个真正的长文件:

1
1
1
1
2
2
2
2
1
1
1
1
2
2
1
1
2
2
...

我有兴趣在每组连续的1上分离和执行计算以及紧随其后的连续2

然而,实际上问题有点复杂。首先,记录不仅仅是12 s,而是更大的东西,让我们说个别Record s,并且需要一些计算来确定是否{{1是} Record1;第二,数据源不是作为文件公开,而是仅通过检索功能公开它,让我们说2。此函数在每次调用时返回一条记录get1 :: IO (Maybe Record),并在数据耗尽时返回Just record;最后,文件很大(实际上是无限的),我必须以流线方式进行,并且内存使用量不断增加。

这是一个假设的成绩单,演示了我希望它的行为方式:( Nothing12来自Record次调用的get1 (,)代表每次检测到组后立即发生的计算)

1
1
1
2
2
1
(["1","1","1"],["2","2"])
2
1
(["1"],["2"])
1
1
1
2
2
2
2
1
(["1","1","1","1"],["2","2","2","2"])

2 个答案:

答案 0 :(得分:4)

以流线型方式收集输入行通常涉及像管道或管道这样的迭代式库。我不熟悉使用管道,但类似的东西可能是通过管道实现的。

首先,有分组的问题。管道使用名为pipes-group的低级库来处理此问题,该库管理分组到子流而不将元素收集到内存中。 (它是pipes-bytestringpipes-text库中类似功能的基础。)

pipes-group通过将输入拆分为使用FreeT分隔的多个生产者来实现此目的。 FreeT基本上允许构建一个"链表"生产者。

import Control.Lens
import Pipes
import Pipes.Group
import qualified Pipes.Prelude as P

main = runEffect $ (concats . view groups) P.stdinLn >-> P.stdoutLn

这将对输入行进行分组(通过(==)),然后立即将它们连接在一起,这不是很有用。为了证明分组确实发生了,我们可以使用intercalates

import Control.Lens
import Pipes
import Pipes.Group
import qualified Pipes.Prelude as P

main = runEffect $
         (intercalates (yield "!") . view groups) P.stdinLn >-> P.stdoutLn

这将输出"!"在每个组之间,至少表明分组正常工作。要一起收集群组的元素,我们使用内置支持foldl库的流媒体折叠:

import Control.Lens
import Pipes
import Pipes.Group
import qualified Pipes.Prelude as P

main = runEffect $
         (folds (++) [] id . view groups) P.stdinLn >-> P.stdoutLn

请注意,虽然stdin将在常量空间中流式传输,但这会将整个组收集到结果列表中的内存中,但当然没有办法避免这种情况。

有关详细信息,请参阅pipes-group tutorialfoldl package

答案 1 :(得分:1)

首先,我没有费心去破译你的代码 - 所以这可能不是你需要的,但希望能够关闭。一个更好的问题应该是一个更好的答案。也就是说,如果你清楚地描述了你想要解决的问题以及你以最直接的方式解决它的难度,而不是展示你在放弃它之前所做的尝试可能有所帮助。

所以你想读取stdin并通过每行上的一些计算对数据进行分组然后对这些组进行计算?这句英语句子几乎直接转化为所需的Haskell:

import Data.List
import Data.Function

main :: IO ()
main = do
  do input <- getContents
     print $ map computation (groupBy ((==) `on` grouper) (lines input))

grouper = id

computation = ("I see a block of stuff of length: " ++) . show . length

输入/输出:

1
1
1
1
1
1
2
2
2
2
2
2
2
2
2
1
["I see a block of stuff of length: 6","I see a block of stuff of length: 9","I see a block of stuff of length: 1"]