如何使用返回Future的函数映射List?

时间:2016-01-12 17:37:16

标签: scala future

我需要Scala Futures和Promises的帮助。我试图从雅虎提取历史数据。我写了一个函数,它接受货币字符串以及开始和结束日期。

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
}

以下是货币清单,我想同时获取这些货币的历史记录。当我尝试运行期货时,我得到了承诺列表,我不知道如何提取。我对Scala Futures和Promises有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")
    }
 }

1 个答案:

答案 0 :(得分: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[...]]

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