【问题标题】:How to merge 2 Enumerators in one, based on merge rule如何根据合并规则将 2 个枚举器合并为一个
【发布时间】:2014-05-31 08:43:46
【问题描述】:

我们在 Playframework 上有一个小型 Scala 项目。我正在尝试做所有反应,并偶然发现了一个问题。

我有两个 Enumerator[A] 实例,代表数据库中按日期排序的值。 我需要将它们作为单个 Enumerator[A] 保持日期排序返回。我在 Enumerator[A] 中没有找到任何解决方案,所以我在单个集合中累积 A,然后对它们进行排序。

case class A(
   created: Date,
   data: String
)

val as: Enumerator[A] = findByAOrderedByCreated()
val bs: Enumerator[A] = findByBOrderedByCreated()

什么是反应式处理这个问题?

【问题讨论】:

    标签: java scala playframework-2.0 enumerator iterate


    【解决方案1】:

    这是一个解决方案,适用于在元素上使用任何 Ordering 的任意数量的 Enumerator 值:

    import play.api.libs.iteratee._
    import scala.concurrent._
    
    object MergeEnums {
      def apply[E: Ordering](enums: Enumerator[E]*)(implicit executor: ExecutionContext) = new Enumerator[E] {
        def apply[A](iter: Iteratee[E, A]) = {
          case class IterateeReturn(o: Option[(Promise[Promise[IterateeReturn]], E)])
    
          val failP = Promise()
          val failPF = failP.future
          val initState = Future.traverse(enums) { enum =>
            val p = Promise[IterateeReturn]()
            enum.run(Iteratee.foldM(p) { (oldP: Promise[IterateeReturn], elem: E) =>
              val p = Promise[Promise[IterateeReturn]]()
              oldP success IterateeReturn(Some(p, elem))
              p.future
            } map { promise =>
              promise success IterateeReturn(None)
            }) onFailure { case t => failP failure t }
            p.future
          } map (_.map(_.o).flatten.toList)
    
          Enumerator.unfoldM(initState) { fstate =>
            Future.firstCompletedOf(Seq(fstate, failPF)) map { state =>
              state.sortBy(_._2) match {
                case Nil => None
                case (oldP, elem) :: tail =>
                  val p = Promise[IterateeReturn]()
                  oldP success p
                  val newState = p.future.map(_.o.map(_ :: tail).getOrElse(tail))
                  Some(newState, elem)
              }
            }
          } apply iter
        }
      }
    }
    

    它创建一个Iteratee 来应用到每个传入的Enumerator,并创建一个Enumerator 来提供排序的元素。 Iteratee 实例和 Enumerator 通过相互发送 Promise 实例进行通信(因此是 Promise[Promise[IterateeReturn]] 等)。

    【讨论】:

    • 谢谢 :) 这意味着来自 Play 技术主管的很多东西。
    • 对不起,我花了很长时间才开始使用它
    • 我们已经在生产环境中使用了上面的wingedsubmariner 的代码一段时间,建议不要使用它。它似乎包含内存泄漏,导致我们的应用程序在与长枚举器一起使用时耗尽内存。由于我们团队中没有人能够理解它,我们也无法调试它。
    猜你喜欢
    • 2021-10-10
    • 2023-02-17
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    相关资源
    最近更新 更多