【问题标题】:How to map over a List using a function returning a Future?如何使用返回 Future 的函数映射列表?
【发布时间】:2016-01-13 02:18:02
【问题描述】:

我需要 Scala 期货和承诺方面的帮助。我正在尝试从雅虎提取历史数据。我写了一个函数,它接受一个货币字符串和一个开始和结束日期。

def getccyHistory(ccy: String, startDate: String, endDate: String): Future[List[HistoricalCurrency]] = Future {     
  val init  = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.historicaldata%20where%20symbol%20%3D%20%22"
  val first = "%3DX%22%20and%20startDate%20%3D%20%22"
  val end   = "%22%20and%20endDate%20%3D%20%22"
  val last  = "%22&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
  val finalString = init + ccy + first + startDate + end + endDate + last
  val histccy = XML.loadString(Source.fromURL(new URL(finalString)).mkString)
  println ("I am in currency {}", ccy)
  (histccy \ "results" \ "quote") map {x => 
    HistoricalCurrency(
      "JPY", (x \ "Date").text, (x \ "Open").text ,(x \ "High").text,
      (x \ "Low").text, (x \ "Close").text) 
  }.toList
}

以下是货币列表,我想同时获取这些货币的历史记录。当我尝试运行期货时,我得到了我不知道如何提取的 Promise 列表。我在 Scala 期货和承诺上有 read quite a bit

val a = List("DKK","JPY","BRL","GBP", "EUR", "SEK")

我附上完整的代码以便于理解。

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.promise
import scala.xml._
import java.net._
import scala.io.Source
import scala.util.{Success, Failure}        

case class HistoricalCurrency(
  val ccy   : String,
  val Date  : String,
  val Open  : String,
  val High  : String,
  val Low   : String,
  val Close : String)


def getccyHistory(ccy: String, startDate: String, endDate: String): Future[List[HistoricalCurrency]] = Future {     
  val init  = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.historicaldata%20where%20symbol%20%3D%20%22"
  val first = "%3DX%22%20and%20startDate%20%3D%20%22"
  val end   = "%22%20and%20endDate%20%3D%20%22"
  val last  = "%22&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
  val finalString = init + ccy + first + startDate + end + endDate + last
  val histccy = XML.loadString(Source.fromURL(new URL(finalString)).mkString)
  println ("I am in currency {}", ccy)
  (histccy \ "results" \ "quote") map {x => 
    HistoricalCurrency(
      "JPY", (x \ "Date").text, (x \ "Open").text ,(x \ "High").text,
      (x \ "Low").text, (x \ "Close").text) 
  }.toList
}       

val a = List("DKK","JPY","BRL","GBP", "EUR", "SEK")

val f = a map {x => getccyHistory(x,"2015-07-12","2016-01-11") }
//> f  : List[scala.concurrent.Future[List[Samples.FutureTest.HistoricalCurrenc
//| y]]] = List(scala.concurrent.impl.Promise$DefaultPromise@306cd243, scala.co
//| ncurrent.impl.Promise$DefaultPromise@3860458b, scala.concurrent.impl.Promis
//| e$DefaultPromise@3875c597, scala.concurrent.impl.Promise$DefaultPromise@3bf
//| f5976, scala.concurrent.impl.Promise$DefaultPromise@794a70bf, scala.concurr
//| ent.impl.Promise$DefaultPromise@63049cf)

f map {x => x.onComplete { case Success(value) => println("Hello")
    }
 }

【问题讨论】:

    标签: scala future


    【解决方案1】:

    您可以使用Future.traverse。这将执行一个函数,为列表(或其他集合)中的每个项目返回一个 Future,并将结果合并到一个 Future

    对于您的货币列表,这将为您提供:

    val getForCurrency: String => Future[List[HistoricalCurrency]] = 
      getccyHistory(_, "2015-07-12","2016-01-11")
    
    Future.traverse(a)(getForCurrency) 
    // scala.concurrent.Future[List[List[HistoricalCurrency]]]
    

    然后你只有一个Future 而不是List[Future[...]]

    您可以使用Future.sequence 将收到的List[Future[...]] 转换为相同的结果,但traverse 只需一步完成映射和排序。

    【讨论】:

    • 谢谢彼得,我能够得到结果。
    猜你喜欢
    • 2013-08-05
    • 2015-10-02
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    • 1970-01-01
    相关资源
    最近更新 更多