【问题标题】:Keep every nth element of a conduit stream保留管道流的每个第 n 个元素
【发布时间】:2016-12-15 17:20:16
【问题描述】:

我正在使用 Conduit 以类似流的方式解析一些数据。在流中的某个时刻,我需要每 12 个元素。有没有方便的方法来做到这一点?

我目前明确地等待 12 个元素返回第一个元素:

get12th :: Monad m => Conduit Int m Int
get12th = loop
  where
    loop = do
        v1 <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        _ <- await
        case v1 of
            Nothing -> return ()
            Just x -> do
              yield x >> loop

它确实有效,但我想知道这是否是最好的方法。

【问题讨论】:

  • 此外,在交付当前元素之前,您最终会等待更多元素(v1 &lt;- await 在底部会更好 - 您的蹦床调用可以处理您应该以 @987654323 开头的事实@)
  • @Alec 我明白你在说什么,我有一个解决方案。但是,我看不出将v1 &lt;- await 移到底部如何解决问题。
  • 在这里,您在发送下一个元素之前等待额外的 11 个元素(您之前收到了 11 个元素!)。移动v1 &lt;- await,一拿到v1就会发送。
  • @Alec 我仍然不明白移动v1 &lt;- await 是如何解决问题的。在你得到v1 并让步之前,做任何事情都是没有意义的。这就是我现在等待v1 的原因。一旦我得到它,我立即让出它,等待另外 11 个值,然后再次循环。但这并不重要,因为这似乎会增加合理的性能损失。
  • @ThomasVanhelden 别担心;您对启发您的解决方案的 cmets 给予了应有的评价,因此没有人会因此而嫉妒您。

标签: haskell conduit


【解决方案1】:

您可以使用replicateM_ 删除那些重复的await 行。

v1 <- await
replicateM_ 11 await
case v1 of
   ...

【讨论】:

  • drop function 可能是相关的。
  • @MichaelSnoyman 好点! Drop 可能更有效,因为它不必在内存中保存值。虽然我不确定replicateM_ 11 await 是否可以。
  • @MichaelSnoyman 你似乎是对的。 drop 函数似乎是最有效的。用replicateM_ 11 await 替换重复的awaits 似乎对性能有(非常轻微的)负面影响。用Data.Conduit.List.drop 11 替换replicateM_11 似乎可以显着提高性能。
  • @MichaelSnoyman 您能否添加使用drop 函数而不是replicateM_ 作为答案,以便我接受?
【解决方案2】:

感谢 Alec、Chad Gilbert 和 Michael Snoyman,我找到了以下解决方案:

get12th :: Monad m => Conduit Int m Int
get12th = loop
  where loop = do
          v <- await
          case v of
            Just x  -> yield x >> CL.drop 11 >> loop
            Nothing -> return ()

此解决方案使用drop 函数来消除重复的等待。它在收到第一个值后立即生成,然后等待其他值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2011-07-11
    • 2021-10-05
    • 2012-11-08
    • 1970-01-01
    • 2012-07-09
    相关资源
    最近更新 更多