【问题标题】:Consolidate a list of Futures into a Map in Scala将期货列表合并到 Scala 中的地图中
【发布时间】:2018-07-29 03:31:12
【问题描述】:

我有两个案例类P(id: String, ...)Q(id: String, ...),以及两个返回期货的函数:

  1. 在给定 id-s 列表的情况下检索对象列表: def retrieve(ids: Seq[String]): Future[Seq[P]] = Future { ... }

    如果没有找到所有 id-s,结果的长度可能会比输入短。

  2. 进一步将P 转换为其他类型Qdef transform(p: P): Future[Q] = Future { ... }

我最后想要的是,以下。给定ids: Seq[String],计算一个Future[Map[String, Option[Q]]]

ids 中的每个id 都应该是映射中的一个键,当它被成功检索(即出现在retrieve 的结果中)并且也成功转换时,id -> Some(q) 应该是一个键。否则,地图应包含id -> NoneEmpty

我怎样才能做到这一点?

【问题讨论】:

    标签: scala list dictionary optional future


    【解决方案1】:

    PQ 上是否有 .id 属性?您需要一个来创建地图。像这样?

    for {
      ps <- retrieve(ids)
      qs <- Future.sequence(ps.map(p => transform(p))
    } yield ids.map(id => id -> qs.find(_.id == id)).toMap
    

    请记住,Map[String,Option[X]] 通常不是必需的,因为如果您有 Map[String,X],则地图上的 .get 方法将为您提供 Option[X]

    【讨论】:

    • qs.find(...)中的线性搜索吗? ;)
    • @AndreyTyukin 是的,也许groupBy(_.id).map(_.head) 更有效率?不知道也不确定是否值得。
    • @AlvaroCarrasco 如果你设法将它包装成Some 并添加withDefaultValue(None),这实际上可能是一种渐近更有效的单线解决方案,很好! :)
    • 谢谢我最终使用了类似的方法,因为它更简单,线性搜索不是问题。
    【解决方案2】:

    编辑:现在假设P 有一个成员id 等于原始id-String,否则ids 和ps 之间的连接在retrieve 之后丢失。

    def consolidatedMap(ids: Seq[String]): Future[Map[String, Option[Q]]] = {
      for {
        ps <- retrieve(ids)
        qOpts <- Future.traverse(ps){
          p => transform(p).map(Option(_)).recover {
            // TODO: don't sweep `Throwable` under the 
            // rug in your real code
            case t: Throwable => None 
          }
        }
      } yield {
        val qMap = (ps.map(_.id) zip qOpts).toMap
        ids.map{ id => (id, qMap.getOrElse(id, None)) }.toMap
      }
    }
    

    从检索到的Ps 构建中间Map 并转换Qs,以便ids-to-q-Options 映射的构建在线性时间内工作。

    【讨论】:

    • 来自 OP:“结果的长度可能比输入的长度短”,zip 在这种情况下不起作用。这就是为什么需要 id。
    • @AlvaroCarrasco 嗯...rIds 可以比ids 短,这是真的。这就是第一个要求之后的评论所说的。但我用rIds 压缩qstraverse 应该返回与 rIds 相同长度的 qs,否则会完全失败。
    • rIds 属于 Seq[P] 类型,不一定与 ids 类型相同
    • 如果transform-s 之一失败,Future.traverse 会发生什么?
    • @BKE 我的问题是“它应该怎么做?”。我不希望代码在吞下一些异常(“格式错误的 id?”等)时用 None(在 DB 中找不到该键的值)来欺骗我
    猜你喜欢
    • 1970-01-01
    • 2020-10-26
    • 2016-07-11
    • 1970-01-01
    • 2021-03-02
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多